在Redux中更新状态后如何触发回调?


85

在React中,状态不会立即更新,因此我们可以在中使用回调setState(state, callback)。但是在Redux中如何做呢?

调用之后this.props.dispatch(updateState(key, value)),我需要立即对更新后的状态进行处理。

有什么方法可以像我在React中那样以最新状态调用回调?


你用thunk吗?
Pranesh Ravi

1
我认为dispatch()是同步活动。更新状态应该在下一行中可用。
Pranesh Ravi

3
@PraneshRavi我是这么认为的。但是我有旧状态。我没用thunk
砖杨


1
是,调度是同步的,但组件的props的后续更新不是同步的。因此,redux状态将在下一行中更新,但是组件的props还没有。
amik

Answers:


112

组件应更新以接收新的道具。

有一些方法可以实现您的目标:

1. componentDidUpdate检查值是否更改,然后执行某些操作。

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

2. redux-promise(中间件将分发promise的已解决值)

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
@DannyHardingdispatch不是同步的。没有Promise.resolve()this.props.value仍会返回旧值。仍然需要某种异步延迟(setTimeout例如,从a进行引用也可以)。
Drazen Bjelovuk

4
@DrazenBjelovuk我想知道,因为在redux-thunk示例中的updateState函数具有dispatch(someAction)并紧随其后的是Promise.resolve()返回。承诺会立即解决,我想这会在redux存储更新和组件中的.then之间创建竞争条件。因为dispatch不会返回promise或接受回调,所以我认为这不是知道redux存储何时更新的准确方法。我认为在这种情况下,正义专家的回答是正确的
Danny Harding '18

2
@DannyHarding是的,我同意这种方法可能不能肯定地保证火灾,只是说明调度是不同步的。
Drazen Bjelovuk

1
我正在尝试在此处使用redux-thunk解决方案,但我只能得到TypeError: _this.props.dispatch is not a function
Krillko

13

关于React的最重要的一点是单向数据流。在您的示例中,这意味着调度动作和状态更改处理应该分开。

您不应该像“我做了A,现在X就成为了Y,我就去处理”那样思考,而是“当X成为时我该做什么Y”,而与无关A。商店状态可以从多个来源进行更新,除了您的组件外,Time Travel还可以更改状态,并且不会通过您的A调度点传递。

基本上,这意味着您应该使用componentWillReceiveProps@Utro提出的建议


这是op确实在寻找的答案(尽管看起来他不知道这一点。)
refaelio

1
我同意,但这个似乎被认为是反模式:hackernoon.com/...
贾科莫Cerquone

1
现在该怎么办componentWillReceivePropsstatic 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

您可以使用subscribe侦听器,并且在分派操作时将调用它。在侦听器内部,您将获取最新的商店数据。

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


2
subscribe仅在分派动作时触发。没有办法subscribe让您知道您的API调用是否返回了任何数据。:D
Mihir

您的请求完成时(成功或不成功),您可以调度另一个操作。
果酱

我不相信这里提出的任何其他解决方案都可以正常工作,因为我看不到状态更新后解决承诺或触发回调的方法。每次商店更新都会调用此方法,不仅是事件之后发生的更新,而且解决起来也不难。尤其是,该链接从您链接到的页面编写了一个自定义的ObservStore实用程序非常有用。
Nat Kuhn

找不到链接页面
Bharat Modi

2

您可以在回调中使用thunk

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

完美满足我的需求!
JSON C11

-1

作为一个简单的解决方案,您可以使用: redux-promise

但是,如果您使用redux-thunk,则应该这样做:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.