突变后如何强制App重新渲染?

时间:2019-06-13 16:04:19

标签: javascript reactjs graphql apollo next.js

我有一个使用Next.js构建的React应用。我希望能够登录,然后使应用程序重新呈现,以便它尝试获取当前已登录的用户。

我的class MyApp extends App { render() { const { Component, pageProps, apolloClient } = this.props; return ( <> <Container> <ApolloProvider client={apolloClient}> <Query query={GET_USER} fetchPolicy="network-only" errorPolicy="ignore"> {({ loading, data, error }) => console.log("rendering app", data) || ( <> <Component {...pageProps} user={data && data.me} /> </> )} </Query> </ApolloProvider> </Container> </> ); } } 组件与apollo提供程序包装在一起,并且还具有一个get用户Query:

<Mutation 
    mutation={LOGIN}
    onError={error => {
        this.setState({error: "Incorrect email or password"})
    }}
    onCompleted={() => {
        window.location.reload() // temp solution to cause app to re-render
    }}
>
  {(login, {loading}) => (
    <Login 
        {...this.props} 
        login={login} 
        loading={loading} 
        error={error} 
    />
  )}
</Mutation>

然后我有一个登录表单,该表单仅将电子邮件和密码发送到我的API,然后返回带有访问令牌的set-cookie令牌标头。

{
  "data": {
    "login": {
      "_id": "abcd1234",
      "accessToken": "abc123",
      "firstName": "First",
      "lastName": "Last",
      "email": "abcd123@b.com",
      "__typename": "User"
    }
  }
}

我可以成功登录,但是我希望Apollo缓存可以写入用户数据:

    def test_threading(self):
        obj = mommy.make(self.model_class)

        def test_concurrency():
            self.model_class.objects.get(id=obj.id)

        t1 = Thread(target=test_concurrency)
        t2 = Thread(target=test_concurrency)

        t1.start()
        t2.start()

        t1.join()
        t2.join()

随着高速缓存的写入,我期望_app.js / ApolloProvider子级在从高速缓存接收道具时重新呈现。

然后,我的获取用户查询应该尝试再次运行(这次在cookie中设置了访问令牌),并且应该返回一个用户(指示该用户已登录)。

为什么我的变体不告诉我的应用重新渲染onCompleted?

1 个答案:

答案 0 :(得分:1)

这是refetchQueries()https://www.apollographql.com/docs/angular/features/cache-updates/#refetchqueries

的理想方案

在您的情况下,您可以将此道具传递给Login突变组件,以在登录后重新获取GET_USER查询。从GET USER中导出_app.js(如果将其放置在User Hoc中,则将其导出到任何位置)。然后在您的登录突变中:

import { GET_USER } from '...'

<Mutation 
    mutation={LOGIN}
    onError={error => {
        this.setState({error: "Incorrect email or password"})
    }}
    onCompleted={() => {
        window.location.reload() // temp solution to cause app to re-render
    }}
    // takes an array of queries to refetch after the mutation is complete
    refetchQueries={[{ query: GET_USER }]} 
>
  {(login, {loading}) => (
    <Login 
        {...this.props} 
        login={login} 
        loading={loading} 
        error={error} 
    />
  )}
</Mutation>

另一种方法是使用update方法将其手动设置为高速缓存,然后保留对该数据的引用或使用高速缓存ID从高速缓存中检索它,从而不必获取更多数据数据,但是refetchQueries非常适合像这样的简单登录突变,这些突变的检索成本并不高。