【问题标题】:How to update Apollo cache after query?查询后如何更新 Apollo 缓存?
【发布时间】:2020-05-11 13:52:02
【问题描述】:

如何覆盖 Apollo 缓存中的值?

我有一个 graphql 查询来获取用户。这将返回具有默认货币的用户。然后可以从选择下拉列表中覆盖该货币。

查询从 API 获取 paymentCurrencies,然后使用客户端解析器将 paymentCurrencies 数组中的第一项设置为用户 currency

query me {
  me {
    username
    currency @client
    paymentCurrencies
  }
}

当有人从下拉菜单中选择一种货币时,我想用他们选择的任何货币覆盖用户的货币。

到目前为止,我有这样的事情:

const onChange = e => {
  const { value } = e.target
  client.writeData({ user: { currency: value, username, __typename: "User" } })
}

我收到以下错误:Error writing result to store for query: {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GeneratedClientQuery"},"selectionSet":null}]} Cannot read property 'selections' of null

使用writeData 是正确的方法还是应该使用writeQuery 之类的?

【问题讨论】:

    标签: javascript reactjs graphql apollo react-apollo


    【解决方案1】:

    如另一个答案中所述,您可能需要一个简单的查询和变异设置。 client 指令用于扩展您的模式以保存仅限客户端的附加数据。根据您的解释,听起来您明确希望将此数据与服务器同步。

    const ME_QUERY = gql`
      query me {
        me {
          username
          currency
          paymentCurrencies
        }
      }
    `;
    
    const CURRENCY_MUTATION = gql`
      mutation setCurrency($currency: String) {
        setCurrency(currency: $currency) {
          me {
            username
            currency
          }
        }
      }
    `;
    
    function MyComponent() {
      const { data } = useQuery(ME_QUERY);
      const [setCurrency] = useMutation(CURRENCY_MUTATION);
    
      const onChange = e => setCurrency({
        variables: { currency: e.currentTarget.value },
      });
    
      return (
        <>
          <h2>{data && data.me.currency}</h2>
          <select onChange={onChange}>
            {/* your dropdown logic */}
          </select>
        </>
      );
    }
    

    你明白了。 Apollo 现在将自动更新您的缓存。确保您的变异允许查询更新的用户对象。

    为了使自动更新工作您的用户需要被缓存识别。您可以通过添加一个 id 字段并在查询和突变中选择它,或者在 Apollo Client 2.x 中实现一个 dataIdFromObject 函数,其中包括 __typename === 'User' 的用户名,或者在 Apollo Client 中使用类型策略来做到这一点3.x。找到docs here

    【讨论】:

    • 那么 setCurrency 会是客户端解析器突变吗?我仍然需要将货币写入缓存的解析器中的逻辑,但不是吗?
    【解决方案2】:

    writeData 应该用于更改根的字段,例如:

    {
      yourState @client
    }
    

    在这种情况下,您应该使用 writeQuery。此外,这个逻辑真的应该被提取到一个(本地)突变中,然后您可以在组件内部调用。使用writeQuery时,基本思路是抓取已有数据,进行复制,然后根据需要进行转换:

    const { me } = client.readQuery({ query: ME_QUERY })
    const data = {
      me: {
        ...me,
        currency: value,
      }
    }
    client.writeQuery({ query: ME_QUERY, data })
    

    您也可以使用writeFragment 直接修改缓存中对象的单个实例。但是,您需要对象的缓存键。因为缓存键派生自 __typenameid 字段,所以您应该确保查询首先包含 id 字段。无论确保您的缓存可以轻松更新,这是一个很好的做法(有关更多详细信息,请参阅here)。然后你可以这样做:

    client.writeFragment({
      id: 'User:42',
      fragment: gql`
        fragment UserCurrency on User {
          currency @client
        }
      `,
      data: {
        currency: value,
      },
    })
    

    【讨论】:

      【解决方案3】:

      视情况而定。

      对于持久更改(同步到服务器),您应该只使用突变更改用户设置。

      对于会话感知更改 - 不要使用用户设置 - 将此(从记录的用户属性)复制到全局应用状态(redux/mobx 或在本例中为 apollo local stateseparate 值) )。

      在这两种情况下,使用更改的数据更新许多组件可能会出现罕见的问题。

      Redux/mobx 自动解决了这个问题。
      Apollo HOC 不会重新渲染。
      钩子 - 部分更新(仅具有 useQueryuseMutation 对的一个),其他将仅在重新渲染时更新。
      使用 &lt;Query/&gt; 构建的组件会在内部创建一个 observable,然后它们也会被更新。

      Mutation 有updaterefetchQueries 参数。 还有一个package 用于更复杂的用例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-26
        • 2017-07-30
        • 2020-05-09
        • 2020-10-22
        • 2018-11-02
        • 2020-02-12
        • 2021-03-24
        • 2022-11-11
        相关资源
        最近更新 更多