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

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

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

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

【问题讨论】:

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

标签: javascript reactjs redux


【解决方案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)
            }
        }
    )
    
    

    【讨论】:

      猜你喜欢
      • 2018-10-04
      • 2016-11-20
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      • 1970-01-01
      • 2019-12-04
      • 2021-09-16
      • 2018-07-21
      相关资源
      最近更新 更多