React Apollo 和 Redux:将自定义 reducer 与 Apollo state 相结合

React Apollo and Redux: Combine custom reducers with Apollo state

在 redux 中使用 react-apollo 时,来自服务器的数据缓存在 redux 存储中的 apollo 键下:

{
    apollo: // results from Apollo queries
}

创建自己的 reducer 和相应的状态树后,您的商店可能如下所示:

{
    apollo: { ... },
    ui: {
        selectedItem: 2;
        showItems: 6
    }
}

假设有一个操作改变了 ui.selectedItem 的值,并且这个值是埋在 apollo 对象某处的项目的索引。

有了 reducer composition,我们 ui 状态的 reducer 将无法访问 Apollo 状态下的任何内容。

在我们的组件中,我们可以通过 mapStateToProps 订阅 ui 状态的变化,我们可以使用 react-apollo GraphQL 容器(或 @graphql装饰器)。

但是我们如何使用根据应用程序中的 Apollo 结果和其他状态计算的值来更新我们的存储?

例如,如果 apollo.item.list 是一个项目数组,而 ui.selectedItem 是您要在该列表中定位的索引 - 存储如何包含以下项的值:

apollo.item.list[ui.selectedItem]

你是对的——使用 reducer 组合,每个 reducer 不应该访问其余的状态。问题是为什么您甚至需要 store 包含 apollo.item.list[ui.selectedItem].

的单独值

大概您需要此值才能在您的容器中呈现正确的项目。要计算它,您只需要一个合适的选择器在 mapStateToProps 中调用。传入整个状态,得到你需要的值。一个简化的例子:

const mapStateToProps = state => ({
  itemToShow: itemSelector(state)
})

const itemSelector = ({ apollo, ui }) => apollo.item.list[ui.selectedItem]

您需要将您的容器包装在 connectgraphql HOC 中才能使其工作,尽管据我所知,无论您将其包装在其中一个还是另一个中首先似乎并不重要。您还可以考虑使用 reselect,它非常适合像这样的派生数据。

编辑: 由于 Apollo 的商店部分并非真正设计用于如上所述的用途,您可能会发现将其分为两个步骤更容易:首先,将 ui.selectedItem 分配给 mapStateToProps 中的道具。然后,如果你用 graphql HOC 包装你的容器,你可以像这样引用那个 prop:

const mapStateToProps = state => ({ selectedItem });
const mapDataToProps = ({ ownProps: { selectedItem }, data }) => ({
  itemToShow: data.item.list[selectedItem]
});
const ContainerWithData = graphql(myQuery, { props: mapDataToProps })(MyContainer);

export default connect(mapStateToProps)(ContainerWithData);

或者您可以使用 apollo-react 的 compose 来获得更简洁的方法。

我的解决方案是使用 recompose 通过 mapProps 将商店和 Apollo 状态一起 compose:

import { mapProps, compose } from ‘recompose’;

const mapStateToProps = state => ({
  selectedItem: state.ui.selectedItem
})

const mapDataToProps = {
  props: ({ data }) => ({ list: data.item.list })
}

const selectProps = mapProps(({ selectedItem, list}) => ({
  item: list[selectedItem] 
}))

export default compose(
  connect(mapStateToProps, {}),
  graphql(MY_QUERY, mapDataToProps),
  selectProps
)(MyComponent);

这也允许我们使用 branch 检查 graphql 加载状态,因此在数据可用之前我们不会 运行 selectProps

感谢 为我指明了正确的方向。

不是您问题的真正答案,但我发现 ReactQL 是一个很棒的入门工具包,可以为您处理所有这些事情。它具有 Apollo+React+Redux 的所有样板,包括定制的 Redux 减速器。看看他们是怎么做到的。