Apollo 客户端和 Redux 设置导致无限渲染循环

Posted

技术标签:

【中文标题】Apollo 客户端和 Redux 设置导致无限渲染循环【英文标题】:Apollo Client and Redux setup causes infinite render loop 【发布时间】:2018-08-10 15:54:26 【问题描述】:

我正在尝试将 React Apollo 与 Redux 连接起来,以便 Apollo 执行查询和突变,并将返回的数据分派到 Redux 存储,以便在应用程序周围分发数据。

我相信我已经接近正确了,但由于某种原因,应用程序进入了 Redux 调度的无限循环,我不知道为什么。

见下面的代码:

class Admin extends Component 
      constructor(props) 
        super(props);
      

      render(
        adminAllTokens
      , ) 
        return ( /* JSX */  )
      );
    
    

    const AllRefreshTokens = gql `
      query 
        allUsers 
          refreshToken
          email
        
      
    `;

    const gqlWrapper = graphql(AllRefreshTokens, 
      props: (
        ownProps,
        data
      ) => 
        ownProps.receivedAdminTokens(data.allUsers); //dispatch to Redux store
        return 
          ...data,
          gqladminAllTokens
        ;
      
    );

    function mapStateToProps(state, ownProps) 
      return 
        adminAllTokens: state.auth.adminAllTokens
      ;
    

    function mapDispatchToProps(dispatch) 
      return 
        receivedAdminTokens: tokens => 
          dispatch(adminTokensReceived(tokens));
        
      ;
    

    const reduxWrapper = connect(mapStateToProps, mapDispatchToProps);
    export default compose(reduxWrapper, gqlWrapper)(Admin);

adminTokensReceived() 动作在 reducer 文件中:

export const adminTokensReceived = tokens => (
    type: 'ADMIN_TOKENS_RECEIVED',
    tokens
);

GraphQL 查询仅发送一个网络请求,但控制台显示ADMIN_TOKENS_RECEIVED 操作不断调度并导致浏览器崩溃。

提前致谢

【问题讨论】:

【参考方案1】:

每当 Apollo HOC 收到新的 props 时,它都会触发你的 action,这会更新 store 并将新的 props 发送到你的 Apollo HOC,这会导致你的 action 触发...

有几种不同的方法可以处理这个问题。在我看来,最直接的方法是放弃graphql HOC 并改用withApollo。比如:

compose(
  withApollo,
  connect(mapStateToProps, mapDispatchToProps)
  lifecycle(
    componentDidMount() 
      const  client  = this.props
      client.query( query: AllRefreshTokens )
        .then((data) => 
          receivedAdminTokens(data.allUsers)
        )
        .catch( //any error handling logic )
    
  )
)

上面使用了 recompose 的 lifecycle,但您也可以轻松地将 componentDidMount 方法粘贴到您的组件中。

也就是说,使用 Redux 来存储 GraphQL 查询的结果似乎有点多余,而 Apollo 已经为你做了。

Apollo 的默认行为是首先从缓存中检索数据,并且仅在数据不存在时才发出网络请求(这也是您只看到一次网络调用的原因)。这意味着您的应用程序中的任意数量的组件都可以使用相同的 graphql HOC 进行包装,并且只有第一个要呈现的组件会触发对您的 GraphQL 端点的请求——所有其他组件将从缓存中获取它们的 data .

【讨论】:

非常感谢您的回复,我明白您的意思了。我正在尝试复制以下回购正在做的事情:github.com/MacKentoch/… - 你知道为什么这能够将它们混合在一起但我的不起作用吗?我明白你说 Redux 有点过时的意思了。 在该示例中,与您在此处尝试执行的操作不同,这些操作被触发以响应突变。 repo 看起来不像是使用 Redux 来持久化查询结果,它依赖于现有的缓存:github.com/MacKentoch/… 好的,感谢您再次回复。我想要包含 redux 的最后一个原因仍然是因为我认为它对于在诸如加载状态之类的东西上设置全局状态很有用。即开始加载和完成加载状态,但我想所有这些都可以由 Apollo 处理。我想知道为什么 repo 甚至使用 redux?

以上是关于Apollo 客户端和 Redux 设置导致无限渲染循环的主要内容,如果未能解决你的问题,请参考以下文章

Apollo 客户端缓存与 Redux

Apollo 客户端的全局加载标志

如何使用 GraphQL 的 Apollo 客户端将获取的数据存储到 Redux 的存储中

从为 GraphQL 分派的 redux 操作中访问 Apollo 客户端

将 redux 客户端从 REST 转换为 GraphQL Apollo?

如何在 React Native 中正确地将 Apollo 客户端连接到 Redux