Next/React-Apollo:当查询来自 getInitialProps 时,React props 没有连接到 apollo 缓存

Next/React-Apollo: React props not hooked up to apollo cache when query comes from getInitialProps

我正在使用 nextjs 和 react-apollo(带钩子)。我正在尝试在突变后更新 apollo 缓存中的用户对象(我不想重新获取)。正在发生的事情是,用户似乎在缓存中得到更新,但组件使用的用户对象没有得到更新。这是相关代码:

页面:

// pages/index.js

...

const Page = ({ user }) => {
  return <MyPage user={user} />;
};


Page.getInitialProps = async (context) => {
  const { apolloClient } = context;
  const user = await apolloClient.query({ query: GetUser }).then(({ data: { user } }) => user);

  return { user };
};

export default Page;

和组件:

// components/MyPage.jsx

...

export default ({ user }) => {
  const [toggleActive] = useMutation(ToggleActive, {
    variables: { id: user.id },
    update: proxy => {
      const currentData = proxy.readQuery({ query: GetUser });

      if (!currentData || !currentData.user) {
        return;
      }

      console.log('user active in update:', currentData.user.isActive);

      proxy.writeQuery({
        query: GetUser,
        data: {
          ...currentData,
          user: {
            ...currentData.user,
            isActive: !currentData.user.isActive
          }
        }
      });
    }
  });

  console.log('user active status:', user.isActive);

  return <button onClick={toggleActive}>Toggle active</button>;
};

当我连续按下按钮时,更新功能中的控制台日志显示用户活动状态来回翻转,所以似乎阿波罗缓存正在正确更新。但是,组件中的控制台日志始终显示相同的状态值。

我没有看到这个问题发生在我正在做的任何其他 apollo 缓存更新中,其中组件使用的数据对象是使用 useQuery 挂钩在组件中获取的(即不是来自 getInitialProps 中的查询) .

请注意,我的 apollo ssr 设置与官方 nextjs 示例非常相似:https://github.com/zeit/next.js/tree/canary/examples/with-apollo

问题是您正在调用客户端的 query 方法。此方法只是向服务器发出请求,并 returns 解析为响应的 Promise。因此 getInitialProps 在页面呈现之前被调用, query 被调用,Promise 解析并且您将生成的用户对象作为道具传递给您的页面组件。对缓存的更新不会触发 getInitialProps 再次成为 运行(尽管我相信导航离开和导航回来应该),因此用户属性在初始渲染后永远不会改变。

如果您想订阅缓存中的更改,而不是使用 query 方法和 getInitialProps,您应该使用 useQuery 挂钩。您也可以使用 Query 组件或 graphql HOC 来达到相同的效果,尽管这两个现在都已弃用,取而代之的是新的挂钩 API.

export default () => {
  const { data: { user } = {} } = useQuery(GetUser)
  const [toggleActive] = useMutation(ToggleActive, { ... })

  ...
})

样板代码中使用的 getDataFromTree 方法(结合设置初始缓存状态)确保使用 useQuery 挂钩为您的页面提取的任何查询都是 运行 页面呈现之前,添加到您的缓存中并用于实际的服务器端呈现。

useQuery 利用客户端的 watchQuery 方法创建一个 observable,它根据缓存的变化进行更新。因此,在组件最初在服务器端呈现后,对客户端缓存的任何更改都将触发组件的重新呈现。