【问题标题】:Wait for redux action to finish dispatching when using redux saga使用 redux saga 时等待 redux action 完成调度
【发布时间】: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
   }

【问题讨论】:

    标签: reactjs redux redux-saga


    【解决方案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)
    猜你喜欢
    • 2019-05-13
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-18
    • 2017-04-18
    • 2019-02-01
    相关资源
    最近更新 更多