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

Posted

技术标签:

【中文标题】变异后如何强制App重新渲染?【英文标题】:How to force App to re-render after mutation? 【发布时间】:2019-10-28 06:50:19 【问题描述】:

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

我的_app.js 组件被 apollo 提供程序包裹,并且还有一个获取用户查询:

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>
      </>
    );
  

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

<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>

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


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

当缓存被写入时,我期待 _app.js / ApolloProvider 孩子在他们从缓存中接收道具时重新渲染。

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

为什么我的突变没有告诉我的应用重新渲染 onCompleted?

【问题讨论】:

为什么不只是setState?这会导致重新渲染 这将导致在本地组件内重新渲染。不是位于组件树顶部的 _app.js 组件 我会将 Apollo Query 放入作为上下文提供者的更高阶组件中。让上下文提供者跟踪用户的登录状态。在那里设置状态。你可以把它放在你的_app.js 好的,但是如何在我的突变后重新运行查询?我还有同样的问题不是吗? 【参考方案1】:

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

在您的场景中,您可以将此道具传递给您的登录突变组件以在登录后重新获取GET_USER 查询。从您的_app.js 中导出GET USER(或者如果您将其放在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 非常适合像这样的简单登录突变,而且检索起来不会太贵。

【讨论】:

以上是关于变异后如何强制App重新渲染?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Angular 2 中强制组件重新渲染?

每次重新加载页面时,如何强制资产渲染资产?

如何强制 linux 上的 chrome 重新计算/重新渲染 ":hover" 样式?

子组件API获取请求后重新渲染App组件?

如何反应原生重新渲染 Flatlist?

vue强制重新渲染