React Apollo 和 Redux:将自定义减速器与 Apollo 状态相结合

IT技术 node.js reactjs react-redux graphql react-apollo
2021-05-26 11:46:09

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

{
    apollo: // results from Apollo queries
}

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

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

想象一下,有一个动作改变了 的值ui.selectedItem,这个值是埋在apollo对象中某处的项目的索引

使用reducer composition,我们uistate 的reducer将无法访问 Apollo 状态下的任何内容。

在我们的组件中,我们可以通过 订阅我们ui状态的变化mapStateToProps,并且我们可以使用react-apolloGraphQL 容器(或@graphql装饰器)将 Apollo 结果映射到 props

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

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

apollo.item.list[ui.selectedItem]
3个回答

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

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

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

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

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

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

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-reactcompose来获得更清洁的方法。

我的解决方案是使用重新合成compose商店和阿波罗通过状态一起mapProps

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);

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

感谢Daniel Rearden 的回答为我指明了正确的方向。

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