如何在 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】:redux
的 dispatch
返回一个承诺,您可以像这样链接。
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 中更新状态后触发回调?的主要内容,如果未能解决你的问题,请参考以下文章