admin管理员组

文章数量:1426794

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.

本文标签: javascriptHow to force App to rerender after mutationStack Overflow