使用 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 完成调度的主要内容,如果未能解决你的问题,请参考以下文章

如何在 redux-saga 中等待另一个动作

如何让 ES6 生成器等待承诺,就像在 redux-saga 中一样?

如何处理进行中的请求以使用redux saga显示加载程序?

redux-saga 的单元测试抛出错误:必须在迭代器上调用 runSaga

手写Redux-Saga源码

redux store 安装 redux-saga 后创建 store 时出错