Як активувати зворотний виклик після оновлення стану в Redux?


86

У React стан не оновлюється миттєво, тому ми можемо використовувати зворотний виклик у setState(state, callback). Але як це зробити в Redux?

Після виклику this.props.dispatch(updateState(key, value)), мені потрібно негайно зробити щось із оновленим станом.

Чи можу я якось викликати зворотний виклик із останнім станом, як те, що я роблю в React?


Ви використовуєте thunk?
Пранеш Раві,

1
Я думаю dispatch(), це синхронна діяльність. Оновлений стан повинен бути доступний у наступному рядку.
Пранеш Раві,

3
@PraneshRavi Я так думав. Але я отримав стару державу. Я не використовував thunk.
Brick Yang


1
Так, відправлення синхронне, але подальше оновлення реквізиту компонента - ні. Тому стан відновлення оновлюється в наступному рядку, але реквізити компонента ще не.
amik

Відповіді:


112

компонент повинен бути оновлений, щоб отримати новий реквізит.

Є способи досягнення вашої мети:

1. componentDidUpdate перевірити, якщо значення змінено, потім зробити щось ..

 componentDidUpdate(prevProps){
     if(prevProps.value !== this.props.value){ alert(prevProps.value) }
  }

2. redux-promis (проміжне програмне забезпечення надішле вирішене значення обіцянки)

export const updateState = (key, value)=>
Promise.resolve({
  type:'UPDATE_STATE',
  key, value
})

то в компоненті

this.props.dispatch(updateState(key, value)).then(()=>{
   alert(this.props.value)
})

2. редукс-думка

export const updateState = (key, value) => dispatch => {
  dispatch({
    type: 'UPDATE_STATE',
    key,
    value,
  });
  return Promise.resolve();
};

то в компоненті

this.props.dispatch(updateState(key, value)).then(()=>{
   alert(this.props.value)
})

6
У вашому redux-thunkприкладі ви використовуєте dispatchтак, ніби це синхронно. Так це?
Danny Harding

2
@DannyHarding dispatchне є синхронним. Без Promise.resolve(), this.props.valueвсе одно поверне старе значення. Потрібна якась асинхронна відстрочка (посилання зсередини setTimeoutтакож також спрацює).
Дражен Бєловук

4
@DrazenBjelovuk Мені цікаво, оскільки функція updateState у прикладі redux-thunk має диспетчеризацію (someAction), за якою слідує return Promise.resolve (). Обіцянка вирішується негайно, що, на мою думку, створить умову перегонів між оновленням магазину redux та викликом .then у компоненті. Оскільки відправка не повертає обіцянки та не приймає зворотний дзвінок, я не думаю, що це точний спосіб дізнатись, коли оновлено сховище redux. Я думаю, що відповідь just-boris у цьому випадку правильна
Денні Хардінг,

2
@DannyHarding Так, я б погодився, що цей метод, швидше за все, не є надійною пожежною гарантією, просто демонструючи, що відправка не є синхронною.
Дражен Бєловук

1
Я намагаюся використовувати тут рішення redux-thunk, але я отримую лише TypeError: _this.props.dispatch is not a function?
Крилько

14

Найважливішим моментом щодо React є односторонній потік даних. У вашому прикладі це означає, що диспетчеризація дії та обробка змін стану повинні бути роз'єднані між собою.

Ви не повинні думати на кшталт "Я це зробив A, тепер Xстаю Yі я з цим справляюся", а "Що я роблю, коли Xстає Y", без будь-якого відношення до A. Стан магазину можна оновити з безлічі джерел, окрім вашого компонента, Подорож у часі також може змінювати стан, і він не буде передаватися через вашу Aточку відправлення.

В основному це означає, що ви повинні використовувати те componentWillReceiveProps, що було запропоновано @Utro


Це відповідь, яку дійсно шукає Оп (хоча, схоже, він цього не знає ..)
refaelio

1
Я погоджуюсь, але це, здається, вважається антипаттерном
Джакомо Серкуоне

1
що ми робимо зараз, що componentWillReceivePropsзастаріло? static getDerivedStateFromProps()не здається підходящою заміною, оскільки він не може викликати зворотний дзвінок, наскільки я можу зрозуміти
M3RS

8

За допомогою API Hooks:

useEffect з опорою як вхідним сигналом.

import React, { useEffect} from 'react'
import { useSelector } from 'react-redux'

export default function ValueComponent() {
   const value = useSelectror(store => store.pathTo.value)

   useEffect(() => {
     console.log('New value', value) 
     return () => {
        console.log('Prev value', value) 
     }

   }, [value])

   return <div> {value} </div>
}

Прийнята відповідь була написана перед React Hooks. Це має бути прийнятою відповіддю вже після введення гачків. Це більш реактивний спосіб обробки змін.
tif

5

Ви можете використовувати subscribeпрослуховувач, і він буде викликаний, коли буде надіслано дію. Усередині прослуховувача ви отримаєте найсвіжіші дані магазину.

http://redux.js.org/docs/api/Store.html#subscribelistener


2
subscribeспрацьовує лише при відправці дії. Ви не subscribeзможете повідомити вас, якщо ваш виклик API повернув якісь дані .. я думаю! : D
Міхір,

Ви можете надіслати ще одну дію, коли ваш запит буде виконано (успішно чи невдало).
Jam

Я не впевнений, що будь-яке з інших запропонованих тут рішень насправді працює, тому що я не бачу способу обіцянки або зворотного дзвінка після оновлення штату. Цей метод викликається для кожного оновлення магазину, не тільки для того, що відбувається після вашої події, але це не повинно бути надто важко обійти. Зокрема, посилання для написання власної утиліти obserStore зі сторінки, на яку ви зробили посилання, дуже корисно.
Nat Kuhn,

Сторінку посилання не знайдено
Бхарат Моді

2

Ви можете використовувати функцію зворотного дзвінка

myThunk = cb => dispatch =>
  myAsyncOp(...)
    .then(res => dispatch(res))
    .then(() => cb()) // Do whatever you want here.
    .catch(err => handleError(err))

Ідеально підходить для того, що мені потрібно!
JSON C11

-1

Як просте рішення ви можете використовувати: redux-promis

Але якщо ви використовуєте redux-thunk , вам слід зробити щось подібне:

function addCost(data) {
  return dispatch => {
    var promise1 = new Promise(function(resolve, reject) {
      dispatch(something);
     });
    return promise1;
  }
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.