使用 redux saga 时等待 redux action 完成调度
Posted
技术标签:
【中文标题】使用 redux saga 时等待 redux action 完成调度【英文标题】:Wait for redux action to finish dispatching when using redux saga 【发布时间】:2019-04-25 04:20:12 【问题描述】:我有一个运行良好的 redux saga 设置。我的调度之一是创建一个新订单,然后一旦创建,我想用更新的状态做事。
// this.props.userOrders = []
dispatch(actions.createOrder(object))
doSomethingWith(this.props.userOrders)
由于 createOrder 操作触发了调用 API 的 redux saga,因此存在延迟,因此在调用我的函数 doSomethingWith 之前不会更新 this.props.userOrders。我可以设置一个超时,但这似乎不是一个可持续的想法。
我已经阅读了有关 Stack Overflow 的类似问题,并尝试实施相关的方法,但我似乎无法让它发挥作用。我希望下面的代码有人可以添加几行就可以了。
以下是相关的其他文件:
actions.js
export const createUserOrder = (data) => ( 类型:'CREATE_USER_ORDER', 数据 )
Sagas.js
function * createUserOrder ()
yield takeEvery('CREATE_USER_ORDER', callCreateUserOrder)
export function * callCreateUserOrder (newUserOrderAction)
try
const data = newUserOrderAction.data
const newUserOrder = yield call(api.createUserOrder, data)
yield put(type: 'CREATE_USER_ORDER_SUCCEEDED', newUserOrder: newUserOrder)
catch (error)
yield put(type: 'CREATE_USER_ORDER_FAILED', error)
Api.js
export const createUserOrder = (data) => new Promise((resolve, reject) =>
api.post('/userOrders/', data, headers: 'Content-Type': 'application/json')
.then((response) =>
if (!response.ok)
reject(response)
else
resolve(data)
)
)
订单减少器:
case 'CREATE_USER_ORDER_SUCCEEDED':
if (action.newUserOrder)
let newArray = state.slice()
newArray.push(action.newUserOrder)
return newArray
else
return state
【问题讨论】:
【参考方案1】:这感觉就像XY Problem。您不应该在任何时候在组件的生命周期函数/事件处理程序中“等待”,而应该利用商店的当前状态。
如果我理解正确,这是您当前的流程:
你在你的 React 组件中调度了一个动作
CREATE_USER_ORDER
。此操作由您的callCreateUserOrder
saga 使用。当您的创建订单传奇完成时,它会调度另一个“已完成”操作,您已经拥有CREATE_USER_ORDER_SUCCEEDED
。
您现在应该添加的是适当的减速器/选择器来处理您的CREATE_USER_ORDER_SUCCEEDED
:
这个CREATE_USER_ORDER_SUCCEEDED
动作应该由你的reducer 来处理,以创建一个新的状态,其中填充了你的状态中的一些“订单”属性。这可以通过选择器直接连接到您的组件,此时您的组件将被重新渲染并填充this.props.userOrders
。
例子:
组件
class OrderList extends React.PureComponent
static propTypes =
userOrders: PropTypes.array.isRequired,
createOrder: PropTypes.func.isRequired,
addOrder()
this.props.createOrder(...)
render()
return (
<Wrapper>
<Button onClick=this.addOrder>Add Order</Button>
<List>this.props.userOrders.map(order => <Item>order.name</Item>)</List>
</Wrapper>
)
const mapStateToProps = state => (
userOrders: state.get('userOrders'),
)
const mapDispatchToProps =
createOrder: () => ( type: 'CREATE_ORDER', payload: ),
export default connect(mapStateToProps, mapDispatchToProps)(OrderList)
减速器
case 'CREATE_USER_ORDER_SUCCEEDED':
return state.update('userOrders',
orders => orders.concat([payload.newUserOrder])
)
如果你确实需要副作用,那么将这些副作用添加到你的 saga 中,或者创建一个新的 saga 来执行 SUCCESS 操作。
【讨论】:
感谢您抽出宝贵时间回复。抱歉,我忘了在我的问题中添加我的减速器,我现在已经在它的底部完成了。你所说的一切我都同意,而且我实际上正在这样做。问题是 this.props.userOrders 更新得不够快,我在代码的下一行使用它,所以我需要“等待”才能知道何时使用它。希望这是有道理的。 只是为了澄清一下,渲染更新的订单不是问题,它直接在 this.props.userOrders 之后做一些事情,这是问题所在。谢谢 @moinhaque 你能举例说明你为什么要“等待”吗?我的意思是你应该重新设计你的方法,这样你就不会“等待”。如果需要,请使用另一个采取成功操作的 saga。不要调度一个动作并立即在组件内的同一个函数中等待它。 我正在使用该调度发出新订单,然后我的下一步是为该订单创建付款,然后用户在应用程序中付款(因此我在零件)。不确定添加另一个 Saga 是否会解决它,但我会调查一下。 一切都很好,但是想象一下,例如,您有一个 POST 应该显示验证错误或导航到另一个页面...并非每个结果都应该触发render()
。 .. 那么如何使用调度/选择器来处理这个问题:this.api.editObject.then(navigate...).catch(...validationErrors)
以上是关于使用 redux saga 时等待 redux action 完成调度的主要内容,如果未能解决你的问题,请参考以下文章
如何让 ES6 生成器等待承诺,就像在 redux-saga 中一样?
如何处理进行中的请求以使用redux saga显示加载程序?