避免具有异步数据依赖性的事件链

Sim*_*ken 13 reactjs reactjs-flux

Facebook Flux调度员明确禁止ActionCreators派遣其他ActionCreator.这种限制可能是一个好主意,因为它会阻止您的应用程序创建事件链.

但是,只要存储包含异步ActionCreator中彼此依赖的数据的存储,就会出现问题.如果不CategoryProductsStore依赖于CategoryStore似乎没有办法避免事件链,而不诉诸推迟后续行动.

场景1: 包含类别中的产品列表的商店需要知道应该从哪个类别ID获取产品.

var CategoryProductActions = {
  get: function(categoryId) {
    Dispatcher.handleViewAction({
      type: ActionTypes.LOAD_CATEGORY_PRODUCTS,
      categoryId: categoryId
    })

    ProductAPIUtils
      .getByCategoryId(categoryId)
      .then(CategoryProductActions.getComplete)
  },

  getComplete: function(products) {
    Dispatcher.handleServerAction({
      type: ActionTypes.LOAD_CATEGORY_PRODUCTS_COMPLETE,
      products: products
    })
  }
}

CategoryStore.dispatchToken = Dispatcher.register(function(payload) {
  var action = payload.action

  switch (action.type) {
    case ActionTypes.LOAD_CATEGORIES_COMPLETE:
      var category = action.categories[0]

      // Attempt to asynchronously fetch products in the given category, this causes an invariant to be thrown.
      CategoryProductActions.get(category.id)

      ...
Run Code Online (Sandbox Code Playgroud)

场景2: 另一种情况是,当存储更改及其componentWillMount/ componentWillReceiveProps 尝试通过异步ActionCreator获取数据时,会挂载子组件 :

var Categories = React.createClass({
  componentWillMount() {
    CategoryStore.addChangeListener(this.onStoreChange)
  },

  onStoreChange: function() {
    this.setState({
      category: CategoryStore.getCurrent()
    })
  },

  render: function() {
    var category = this.state.category

    if (category) {
      var products = <CategoryProducts categoryId={category.id} />
    }

    return (
      <div>
        {products}
      </div>
    )
  }
})

var CategoryProducts = React.createClass({
  componentWillMount: function() {
    if (!CategoryProductStore.contains(this.props.categoryId)) {
      // Attempt to asynchronously fetch products in the given category, this causes an invariant to be thrown.
      CategoryProductActions.get(this.props.categoryId)
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

有没有办法避免这种情况而不诉诸推迟?

fis*_*dev 3

每当您检索应用程序的状态时,您都希望使用 getter 方法直接从 Store 检索该状态。操作是通知存储的对象。您可以将它们视为状态更改的请求。他们不应该返回任何数据。它们不是您检索应用程序状态的机制,而只是更改它。

因此,在场景 1中,getCurrent(category.id)是应该在 Store 上定义的内容。

场景 2中,听起来您遇到了 Store 数据初始化的问题。我通常通过(理想情况下)在渲染根组件之前将数据放入存储中来处理这个问题。我在引导模块中执行此操作。或者,如果这绝对需要异步,您可以创建所有内容以使用空白板,然后在商店响应操作后重新渲染INITIAL_LOAD

  • 我认为对于在哪里可以调用 API 获取更多数据存在一些困惑。在商店里这样做是可以的。重要的是要确保当数据返回时,您可以通过操作进入流程,而不是直接修改存储。这确保了存储能够控制自己,并且任何其他存储都可以通过 Flux 方式获知相同的新数据。 (4认同)
  • 我已经阐明了这两个示例,在这两种情况下,获取类别中的产品的 ActionCreator 都会触发异步 API 操作。因此,在场景 #1 中,我首先从 API 获取类别列表,然后也通过 API 获取该类别中的产品。对于场景#2,我做了同样的事情,但仅当组件已安装并且需要数据时。我不知道该组件何时安装,因此无法将数据获取到根组件中。 (2认同)