Javascript Apollo是否缓存突变返回的数据

Javascript Apollo是否缓存突变返回的数据,javascript,reactjs,graphql,react-apollo,apollo-client,Javascript,Reactjs,Graphql,React Apollo,Apollo Client,我在React应用程序中使用Apollo客户端,我需要进行变异,然后保留返回的数据供以后使用(但我无法访问变量),我是否必须使用其他状态管理解决方案,或者我们可以在Apollo中执行此操作 我读过关于用查询而不是变异来实现这一点的文章 这是到目前为止我的代码 // Mutation const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, { onCompleted({ myMutation }) {

我在React应用程序中使用Apollo客户端,我需要进行变异,然后保留返回的数据供以后使用(但我无法访问变量),我是否必须使用其他状态管理解决方案,或者我们可以在Apollo中执行此操作

我读过关于用查询而不是变异来实现这一点的文章

这是到目前为止我的代码

// Mutation
const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, {
    onCompleted({ myMutation }) {
      console.log('myMutation: ', myMutation.dataToKeep);
      if (myMutation && myMutation.dataToKeep)
        SetResponse(myMutation.dataToKeep);
    },
    onError(error) {
      console.error('error: ', error);
    },
  });

//How I call it

  onClick={() => {
    myMutation({
      variables: {
        input: {
          phoneNumber: '0000000000',
          id: '0000',
        },
      },
    });
  }}

编辑:

这是突变

export const MY_MUTATION = gql`
  mutation MyMutation($input: MyMutationInput!) {
    myMutation(input: $input) {
      dataToKeep
      expiresAt
    }
  }
`;
以及这种突变的模式

MyMutationInput:
  phoneNumber: String!
  id: String!

MyMutationPayload:
  dataToKeep
  expiresAt
  
案例1:有效负载正在使用公共实体 简单地说,Apollo客户端的缓存保留了从查询和突变中接收到的所有内容,尽管模式需要包含
id:id字段和任何查询都需要使用相关节点上的
id
\uuuu typename
字段,以便客户端知道要更新缓存的哪个部分

这假设变异负载是来自模式的公共数据,可以通过正常查询检索。这是最好的情况

给定服务器上的以下架构:

type User {
  id: ID!
  phoneNumber: String!
}

type Query {
  user(id: String!): User!
}

type UpdateUserPayload {
  user: User!
}

type Mutation {
  updateUser(id: String!, phoneNumber: String!): UpdateUserPayload!
}
假设:

  • 响应中包含的每个可识别对象的缓存

  • 缓存按ID将对象存储在平面查找表中

  • 每当传入对象以与现有对象相同的ID存储时,这些对象的字段就会合并

    • 如果传入对象和现有对象共享任何字段,则传入对象将覆盖这些字段的缓存值
    • 仅出现在现有对象或仅出现在传入对象中的字段将被保留
  • 规范化在数据库上构造数据图的部分副本 客户端,其格式针对读取和更新 在应用程序更改状态时绘制图形

    客户的突变应该是

    mutation UpdateUserPhone($phoneNumber: String!, $id: String!) {
      updateUser(id: $id, phoneNumber: $phoneNumber) {
        user {
          __typename  # Added by default by the Apollo client
          id          # Required to identify the user in the cache
          phoneNumber # Field that'll be updated in the cache
        }
      }
    }
    

    然后,通过应用程序中相同的Apollo客户端使用此用户的任何组件都将自动更新。没有什么特别的事情要做,客户机将默认使用缓存,并在数据更改时触发渲染

    从'@apollo/client'导入{gql,useQuery};
    const USER_QUERY=gql`
    查询GetUser($id:String!){
    用户(id:$id){
    __字体名
    身份证件
    电话号码
    }
    }
    `;
    const UserComponent=({userId})=>{
    const{loading,error,data}=useQuery(用户查询{
    变量:{id:userId},
    });
    if(加载)返回null;
    if(error)返回`error!${error}`;
    返回{data.user.phoneNumber};
    }
    
    默认设置为先缓存


    案例2:负载是特定于突变的自定义数据 如果该数据实际上在模式的其他地方不可用,那么就不可能像上面解释的那样自动使用Apollo缓存

    使用其他状态管理解决方案 有两种选择:

    • 本地存储
    • 等等
    下面是一个使用
    localStorage
    的示例:

    const[login,{loading,error}]=useCommutation(login\u USER{
    未完成({login}){
    localStorage.setItem('token',login.token);
    setItem('userId',login.id);
    }
    });
    
    这是一个纯Apollo GraphQL解决方案,因为客户端也是一个状态管理库,它支持有用的开发人员工具,并有助于对数据进行推理

  • 创建本地模式

    // schema.js
    export const typeDefs = gql`
      type DataToKeep {
        # anything here
      }
    
      extend type Query {
        dataToKeep: DataToKeep # probably nullable?
      }
    `;
    
  • 初始化自定义缓存

    // cache.js
    export const dataToKeepVar = makeVar(null);
    
    export const cache = new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            dataToKeep: {
              read() {
                return dataToKeepVar();
              } 
            },
          }
        }
      }
    });
    
  • 在客户端初始化时应用架构覆盖

    import { InMemoryCache, Reference, makeVar } from '@apollo/client';
    import { cache } from './cache';
    import { typeDefs } from './schema';
    
    const client = new ApolloClient({
      cache,
      typeDefs,
      // other options like, headers, uri, etc.
    });
    
  • 跟踪突变的变化:

    const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, {
      onCompleted({ myMutation }) {
        if (myMutation && myMutation.dataToKeep)
          dataToKeepVar(myMutation.dataToKeep);
      }
    });
    
  • 然后,查询
    @client
    字段

    import { gql, useQuery } from '@apollo/client';
    
    const DATA_QUERY = gql`
      query dataToKeep {
        dataToKeep @client {
          # anything here
        }
      }
    `;
    
    const AnyComponent = ({ userId }) => {
      const { loading, error, data } = useQuery(DATA_QUERY);
    
      if (loading) return null;
      if (error) return `Error! ${error}`;
    
      return <div>{JSON.stringify(data.dataToKeep)}</div>;
    }
    
    从'@apollo/client'导入{gql,useQuery};
    const DATA_QUERY=gql`
    查询datatokep{
    dataToKeep@client{
    #这里有什么吗
    }
    }
    `;
    const AnyComponent=({userId})=>{
    const{loading,error,data}=useQuery(数据查询);
    if(加载)返回null;
    if(error)返回`error!${error}`;
    返回{JSON.stringify(data.dataToKeep)};
    }
    

  • 另请参阅有关的文档。

    您使用的是哪一版本的apollo客户端?你说的以后使用是什么意思?你的意思是像一个全局状态保存在应用程序中,或者更像一个需要在不同组件之间共享的状态?@ManuelPamplona我使用的是3.2.9“那么,通过应用程序中相同的Apollo客户端使用此用户的任何组件都将自动更新。”我如何在缓存中访问此用户?@Mel无需特别说明,我添加了一个默认情况下使用缓存的简单示例。当我按照您的示例创建新查询时,我会收到“消息”:“字段“myMutation”不存在于“query”类型上,因为API中没有此名称的查询。我遗漏了什么?@Mel好的,在挖掘了一点之后,我加入了另外两个解决方案:使用另一个状态管理解决方案,就像你建议的,以及使用一个本地状态,因为Apollo客户端库也是一个状态管理库。我最终使用了上下文,但你的答案正是我一开始想要做的,谢谢
    import { gql, useQuery } from '@apollo/client';
    
    const DATA_QUERY = gql`
      query dataToKeep {
        dataToKeep @client {
          # anything here
        }
      }
    `;
    
    const AnyComponent = ({ userId }) => {
      const { loading, error, data } = useQuery(DATA_QUERY);
    
      if (loading) return null;
      if (error) return `Error! ${error}`;
    
      return <div>{JSON.stringify(data.dataToKeep)}</div>;
    }