Как отключить обратный вызов после обновления состояния в Redux?

86

В React состояние не обновляется мгновенно, поэтому мы можем использовать обратный вызов в setState(state, callback). Но как это сделать в Redux?

После вызова this.props.dispatch(updateState(key, value))мне нужно немедленно что-то сделать с обновленным состоянием.

Есть ли способ вызвать обратный вызов с последним состоянием, как то, что я делаю в React?

Кирпич Ян
источник
Вы пользуетесь thunk?
Пранеш Рави
1
Думаю dispatch(), это синхронная деятельность. Обновленное состояние должно быть доступно в следующей строке.
Пранеш Рави
3
@PraneshRavi Я так и думал. Но мне досталось старое состояние. Я не использовал thunk.
Брик Ян
1
Да, отправка выполняется синхронно, но последующее обновление свойств компонента - нет. Таким образом, в следующей строке обновляется состояние redux, а свойства компонента еще нет.
амик

Ответы:

112

компонент должен быть обновлен, чтобы получать новые реквизиты.

есть способы достичь своей цели:

1. componentDidUpdate проверяет, изменилось ли значение, затем что-то делать ..

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

2. redux-обещание (промежуточное программное обеспечение отправляет разрешенное значение обещания)

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

затем в компоненте

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

2. redux-thunk

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как если бы он был синхронным. Так ли это?
Дэнни Хардинг
2
@DannyHarding dispatchне синхронный. Без Promise.resolve(), this.props.valueвсе равно возвращает старое значение. Какая-то асинхронная отсрочка все еще необходима (например, ссылка изнутри также setTimeoutбудет работать).
Дражен Беловук
4
@DrazenBjelovuk Мне интересно, потому что функция updateState в примере redux-thunk имеет dispatch (someAction), за которым сразу следует return Promise.resolve (). Обещание разрешается немедленно, что, как я полагаю, создало бы состояние гонки между обновлением хранилища redux и .then, вызываемым в компоненте. Поскольку отправка не возвращает обещание и не принимает обратный вызов, я не думаю, что это точный способ узнать, когда хранилище redux было обновлено. Я думаю, что ответ Just-Boris в данном случае правильный
Дэнни Хардинг
2
@DannyHarding Да, я согласен, что этот метод, скорее всего, не является надежной гарантией огня, просто демонстрируя, что отправка не синхронна.
Drazen Bjelovuk
1
Я пытаюсь использовать здесь решение redux-thunk, но получаю только TypeError: _this.props.dispatch is not a function?
Krillko
14

Самый важный момент в React - это односторонний поток данных. В вашем примере это означает, что отправка действия и обработка изменения состояния должны быть разделены.

Вы не должны думать, как «Я сделал A, теперь Xстановится, Yи я справляюсь с этим», а «Что мне делать, когда Xстановится Y», без какого-либо отношения к A. Состояние хранилища может быть обновлено из нескольких источников, помимо вашего компонента, Time Travel также может изменять состояние, и оно не будет передано через вашу Aточку отправки.

В основном это означает, что вы должны использовать, componentWillReceivePropsкак это было предложено @Utro

Just-Boris
источник
Это тот ответ, который op действительно ищет (хотя, похоже, он об этом не знает ..)
refaelio
1
Я согласен, но это, похоже, считается антипаттерном: hackernoon.com/…
Джакомо Черкуоне
1
что нам делать теперь, что componentWillReceivePropsустарело? static getDerivedStateFromProps()не кажется подходящей заменой, поскольку он не может вызывать обратный вызов, насколько я могу судить
M3RS
7

С помощью Hooks API:

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

Вы можете использовать subscribelistener, и он будет вызываться при отправке действия. Внутри слушателя вы получите последние данные магазина.

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

Пранеш Рави
источник
2
subscribeсрабатывает только при отправке действия. Нет никакого способа subscribeсообщить вам, вернул ли ваш вызов API какие-либо данные ... я думаю! : D
Михир
Вы можете отправить другое действие, когда ваш запрос будет завершен (успешно или безуспешно).
Jam
Я не уверен, что какие-либо другие предлагаемые здесь решения действительно работают, потому что я не вижу способа выполнить обещание или выполнить обратный вызов после обновления состояния. Этот метод вызывается для каждого обновления магазина, а не только для того, которое происходит после вашего события, но это не должно быть слишком сложно обойти. В частности, очень полезна ссылка для написания пользовательской утилиты ObserverStore со страницы, на которую вы ссылаетесь .
Nat Kuhn
Страница со ссылками не найдена
Бхарат Моди
2

Вы можете использовать преобразователь с обратным вызовом

myThunk = cb => dispatch =>
  myAsyncOp(...)
    .then(res => dispatch(res))
    .then(() => cb()) // Do whatever you want here.
    .catch(err => handleError(err))
Acmoune
источник
Идеально подходит для того, что мне было нужно!
JSON C11
-1

В качестве простого решения вы можете использовать: redux-обещание

Но если вы используете redux-thunk , вы должны сделать что-то вроде этого:

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

Мохаммад П.
источник