查询后如何更新Apollo缓存?

时间:2020-01-25 14:01:31

标签: javascript reactjs graphql apollo react-apollo

如何覆盖Apollo缓存中的值?

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

查询从API提取image = pygame.image.load("boomerang64.png") pos = (200, 200) angle = 0 while True: # [...] rotate_rect, rotate_image = ???? # rotate around green cross by angle surf.blit(rotated_image, rotate_rect) angle += 1 # [...] ,然后使用客户端解析器将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之类的东西?

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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,
  },
})

答案 2 :(得分:0)

这取决于。

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

要了解会话更改-不要使用用户设置-将此(从记录的用户属性中)复制到全局应用程序状态(redux / mobx或在这种情况下,阿波罗{{3 }}。

在这两种情况下,罕见的问题都是使用更改后的数据更新许多组件。

Redux / mobx自动解决此问题。
Apollo HOC不会重新呈现。
挂钩-部分更新(仅具有useQueryuseMutation对的挂钩),其他仅在重新渲染时才会更新。
使用<Query/>构建的组件会在内部创建一个可观察的组件,然后它们也会被更新。

突变具有updaterefetchQueries参数。 对于更复杂的用例,还有一个local state