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

Posted

技术标签:

【中文标题】如何在 Redux 中更新状态后触发回调?【英文标题】:How to trigger off callback after updating state in Redux? 【发布时间】:2017-01-24 06:59:28 【问题描述】:

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

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

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

【问题讨论】:

你使用thunk吗? 我认为dispatch() 是一个同步活动。更新后的状态应该在下一行中可用。 @PraneshRavi 我是这么认为的。但我得到了旧的状态。我没有使用thunk Redux dispatch is synchronous. 是的 dispatch 是同步的,但是组件的 props 的后续更新不是。因此 redux 状态在下一行更新,但组件的 props 还没有。 【参考方案1】:

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

有多种方法可以实现您的目标:

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)
)

【讨论】:

在您的redux-thunk 示例中,您使用dispatch,就好像它是同步的一样。是这样吗? @DannyHarding dispatch 不是同步的。如果没有Promise.resolve()this.props.value 仍将返回旧值。仍然需要某种异步延迟(例如,从 setTimeout 中引用也可以)。 @DrazenBjelovuk 我想知道,因为 redux-thunk 示例中的 updateState 函数有 dispatch(someAction) 紧跟 return Promise.resolve()。承诺立即解决,我想这会在 redux 存储更新和组件中调用的 .then 之间创建竞争条件。因为 dispatch 不返回承诺或接受回调,所以我认为这不是了解 redux 存储何时更新的准确方法。我认为在这种情况下,just-boris 的答案是正确的 @DannyHarding 是的,我同意这种方法可能不是一个可靠的保证,只是说明调度不是同步的。 我在这里尝试使用redux-thunk解决方案,但我只得到TypeError: _this.props.dispatch is not a function?【参考方案2】:

使用 Hooks API:

useEffect 以 prop 作为输入。

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

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

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

   , [value])

   return <div> value </div>

【讨论】:

接受的答案是在 React Hooks 之前编写的。在引入钩子之后,这应该是现在公认的答案。这是一种更被动的方式来处理更改。 不一定。如果您想在按钮单击时触发具有更新存储数据的函数,但又不想在每次特定数据发生更改时触发该函数? 同意@mkatanski,每次都使用效果触发,这样处理不太自然【参考方案3】:

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

你不应该这样想“我做了A,现在X变成了Y并且我处理它”,而是“当X变成Y时我该怎么办”,与A。存储状态可以从多个来源更新,除了你的组件,时间旅行也可以改变状态,它不会通过你的A调度点。

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

【讨论】:

这是 op 真正要寻找的答案(尽管他似乎没有意识到这一点..) 我同意,但这似乎被认为是一种反模式:hackernoon.com/… componentWillReceiveProps 已被弃用,现在我们该怎么办? static getDerivedStateFromProps() 似乎不是一个合适的替代品,因为它不能调用回调,据我所知【参考方案4】:

您可以使用subscribe 侦听器,它会在分派操作时调用。在侦听器中,您将获得最新的商店数据。

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

【讨论】:

subscribe 仅在调度操作时触发。 subscribe 不可能让您知道您的 API 调用是否返回了任何数据.. 我想! :D 您可以在您的请求完成(成功或不成功)时调度另一个操作。 我不相信这里提出的任何其他解决方案确实有效,因为我看不到在状态更新后解决承诺或触发回调的方法。每次商店更新都会调用此方法,而不仅仅是在您的活动之后发生的更新,但这不应该太难解决。特别是,您链接到的页面中的链接write a custom observeStore utility 非常有帮助。 链接页面未找到 这是使用基于函数的组件时的首选..【参考方案5】:

您可以使用带有回调的 thunk

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

【讨论】:

非常适合我的需要!【参考方案6】:

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

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

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

【讨论】:

【参考方案7】:

reduxdispatch 返回一个承诺,您可以像这样链接。

     const submissionPromise: any = dispatch(submitFundRequest())
        submissionPromise
            .then((response: any) => 
                if(response.error) 
                    return console.log('There was an error', response)
                
                Swal.fire(
                    title: 'Submission',
                    text: 'You have successfully submitted the requisition'
                )
            )
            .catch((err: any) => 
                console.log('Submission failed', err)
            )

response.error 仅在 thunk 被拒绝时设置。在您的submitFundRequest thunk 中,您可以执行类似的操作来拒绝。

export const submitFundRequest = createAsyncThunk(
    'fundRequest/submitFundRequest',
    async function submit(payload, thunkAPI) 
        try 
            ...
         catch(e: any) 
            const error =  message: e.response.statusMessage 
            return thunkAPI.rejectWithValue(error)
        
    
)

【讨论】:

以上是关于如何在 Redux 中更新状态后触发回调?的主要内容,如果未能解决你的问题,请参考以下文章

从 redux 更改状态后如何以及何时调用反应组件方法

如何在 mapDispatchToProps 或更新道具后运行回调函数,使用 react redux?

如何使用从子组件传递给组件的反应变量更新 redux 状态

如何在 redux 状态更新时自动刷新组件

java中,支付成功后要进行数据库的修改,如何做?

thunk 和 action 完成后如何使用 redux 的当前状态?