最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to force App to re-render after mutation? - Stack Overflow

programmeradmin0浏览0评论

I have a React app built using Next.js. I want to be able to login and then cause the app to re-render in order for it to attempt to fetch the current logged in user.

My _app.js ponent is wrapped with the apollo provider and has a get user Query as well:

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

I then have a login form which simply sends the email and password to my API which then returns a set-cookie token header with the access token.

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

I can successfully log in but I was expecting the Apollo cache to get written to with the user data:

{
  "data": {
    "login": {
      "_id": "abcd1234",
      "accessToken": "abc123",
      "firstName": "First",
      "lastName": "Last",
      "email": "[email protected]",
      "__typename": "User"
    }
  }
}

As the cache is getting written to, I was expecting the _app.js / ApolloProvider children to re-render as they receive props from the cache.

My get user Query should then attempt to run again (this time with the access token set in a cookie) and a user should be returned (indicating the user is logged in).

Why is my mutation not telling my app to re-render onCompleted?

I have a React app built using Next.js. I want to be able to login and then cause the app to re-render in order for it to attempt to fetch the current logged in user.

My _app.js ponent is wrapped with the apollo provider and has a get user Query as well:

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

I then have a login form which simply sends the email and password to my API which then returns a set-cookie token header with the access token.

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

I can successfully log in but I was expecting the Apollo cache to get written to with the user data:

{
  "data": {
    "login": {
      "_id": "abcd1234",
      "accessToken": "abc123",
      "firstName": "First",
      "lastName": "Last",
      "email": "[email protected]",
      "__typename": "User"
    }
  }
}

As the cache is getting written to, I was expecting the _app.js / ApolloProvider children to re-render as they receive props from the cache.

My get user Query should then attempt to run again (this time with the access token set in a cookie) and a user should be returned (indicating the user is logged in).

Why is my mutation not telling my app to re-render onCompleted?

Share Improve this question asked Jun 13, 2019 at 16:04 Stretch0Stretch0 9,31315 gold badges94 silver badges159 bronze badges 4
  • 2 Why not just setState? That would cause a re-render – Max Baldwin Commented Jun 13, 2019 at 16:06
  • This would cause a re-render within the local ponent. Not the _app.js ponent which is at the top of the ponent tree – Stretch0 Commented Jun 13, 2019 at 16:14
  • I would put the Apollo Query into a higher order ponent that is a context provider. Have that context provider keep track of the user's login status. Set state in there. You can have it in your _app.js – Max Baldwin Commented Jun 13, 2019 at 16:30
  • OK but how do I make the query re run after my mutation? I still have to same problem don't I? – Stretch0 Commented Jun 13, 2019 at 16:39
Add a ment  | 

1 Answer 1

Reset to default 4

This is the perfect scenario for refetchQueries(): https://www.apollographql./docs/angular/features/cache-updates/#refetchqueries

In your scenario, you could pass this prop to your Login mutation ponent to refetch the GET_USER query after login. Export the GET USER from your _app.js (or wherever you're moving it to if you're putting it in a User Hoc). Then in your login mutation:

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 plete
    refetchQueries={[{ query: GET_USER }]} 
>
  {(login, {loading}) => (
    <Login 
        {...this.props} 
        login={login} 
        loading={loading} 
        error={error} 
    />
  )}
</Mutation>

The other alternative is to use the update method to manually set it to the cache and then keep a reference to that data or retrieve it from the cache with a cache id so you don't have to fetch more data, but the refetchQueries is perfect for simple login mutations like this that aren't too expensive to retrieve.

发布评论

评论列表(0)

  1. 暂无评论