首页 > 解决方案 > React Apollo - 孩子没有根据结果变化进行更新

问题描述

我正在使用 React Apollo 来处理 GaphQL 后端。我正在创建的功能允许用户编辑另一个用户的管理员权限。

我有两个组件。一个组件包含 React Apollo 逻辑,包括查询和突变组件。当这个组件被渲染时,从路由器中的 match 参数向下传递的 prop 指定在 GraphQL 查询中使用哪个管理员来获取其权限。当检索到管理员权限组件所需的数据时,它将作为道具传递给子组件,该子组件根据该道具设置初始状态。子组件不包含 React Apollo 逻辑,仅包含复选框和其他输入,这些输入会在组件状态更改时更新它们。单击保存更改按钮时,调用父级的变异函数,传递新更新的权限以将变量插入变异查询。

我面临的问题是,有时状态不会根据道具而改变。例如,访问管理员 1,然后路由器会在单击按钮以访问管理员 2 时更新 URL。它一直工作到此为止。然后,当单击按钮访问 admin 1 时,路由器会再次更新 URL,尽管 props 已使用新值更新,但 admin 2 仍显示在子组件中。注意子组件的构造函数不会被再次调用。

关于如何确保 GraphQL 查询生成的数据显示正确的子组件实例的任何建议?此外,关于如何改进该组件的结构的任何建议。

render(){
if(this.props.steamID ===  null) return null;

const QUERY_VARIABLES = {
  serverID: this.props.serverID,
  selectedAdminSteamID: this.props.steamID,
  currentAdminSteamID: Auth.claim.steamID
};

return (
  <Query
    query={QUERY}
    variables={QUERY_VARIABLES}
  >
    {({ loading, error, data }) => {
      if (loading) return ( ... );
      if (error) return ( ... );
      if(!data.server.selectedAdmin) return ( ... );

      return (
        <Mutation
          mutation={MUTATION}
          update={(cache, { data: { updateAdminPermission } }) => {
            const data = cache.readQuery({ query: QUERY, variables: QUERY_VARIABLES });
            data.server.selectedAdmin = updateAdminPermission;
            cache.writeQuery({ query: QUERY, variables: QUERY_VARIABLES, data: data, });
          }}
        >

          {(updateAdminPermission, { loading, error }) => (
            <>
              <AdminPermissions
                serverID={this.props.serverID}
                steamID={this.props.steamID}

                selectedAdmin={data.server.selectedAdmin}
                currentAdmin={data.server.currentAdmin}

                updatePermissionFunction={(variables) => {
                  updateAdminPermission({ variables })
                }}
                updatePermissionLoading={loading}
              />
              <GraphQLErrorModal error={error} />
            </>
          )}

        </Mutation>
      );
    }}
  </Query>
);
}

class AdminPermissions extends React.Component{
    constructor(props){
      super();

      this.state = props.selectedAdmin;

      this.guid = React.createRef();
      this.updatePermission = this.updatePermission.bind(this);
      this.saveChanges = this.saveChanges.bind(this);
    }

    updatePermission(changedPermission, value){
      if(changedPermission === 'manageAssignPermissions' && value > 0){
        for(let permission of panelPermissions.concat(gamePermissions)){
          if(permission.permission === 'manageAssignPermissions') continue;
          this.setState({ [permission.permission]: 2 });
        }
      }
      this.setState({ [changedPermission]: value });
    }

    saveChanges(){
      this.props.updatePermissionFunction({
        serverID: this.props.serverID,
        steamID: this.props.steamID,
        guid: this.guid.current.value,
        ...this.state
      });
    }

    render(){
        // renders pairs of checkboxes with checked value based on state and on change event that calls update permissions method passing the name of the associated permission and a value that is calculated based on which boxes in the pair are ticked.
    }
 }

查询(更新)

  query AdminPermission($serverID: Int!, $selectedAdminSteamID: String!, $currentAdminSteamID: String!) {
    server(id: $serverID) {
      id

      selectedAdmin: adminPermission(steamID: $selectedAdminSteamID) {    
        _id

        admin {
          _id

          steamID
          displayName
          avatar
        }

        player {
          _id
          guid
        }

        manageAssignPermissions
        viewAdminPermissions
        ...
      }
      currentAdmin: adminPermission(steamID: $currentAdminSteamID) {
        _id

        admin {
          _id
          steamID
        }

        manageAssignPermissions
        viewAdminPermissions
        ...
      }
    }
  }

标签: javascriptreactjsreact-apollo

解决方案


您必须将Query's设置fetchPolicycache-and-network,默认情况下它是cache-first

<Query
    query={QUERY}
    variables={QUERY_VARIABLES}
    fetchPolicy='cache-and-network'
  >

如果您阅读 文档

  • cache-first:这是我们总是首先尝试从缓存中读取数据的默认值。如果完成查询所需的所有数据都在缓存中,则将返回该数据。如果缓存的结果不可用,Apollo 只会从网络中获取。此获取策略旨在最大限度地减少渲染组件时发送的网络请求数量。

  • cache-and-network:此获取策略将让 Apollo 首先尝试从您的缓存中读取数据。如果完成查询所需的所有数据都在缓存中,则将返回该数据。但是,无论完整数据是否在您的缓存中,此 fetchPolicy 将始终使用网络接口执行查询,这与 cache-first 不同,后者仅在查询数据不在您的缓存中时才会执行您的查询。此获取策略优化了用户获得快速响应,同时还尝试以额外的网络请求为代价使缓存数据与您的服务器数据保持一致。


推荐阅读