简体   繁体   中英

React, Apollo 2, GraphQL, Authentication. How to re-render component after login

I have this code: https://codesandbox.io/s/507w9qxrrl

I don't understand:

1) How to re-render() Menu component after:

this.props.client.query({
  query: CURRENT_USER_QUERY,
  fetchPolicy: "network-only"
});

If I login() I expect my Menu component to re-render() itself. But nothing. Only if I click on the Home link it re-render() itself. I suspect because I'm using this to render it:

<Route component={Menu} />

for embrace it in react-router props. Is it wrong?

Plus, if inspect this.props of Menu after login() I see loading: true forever. Why?

2) How to prevent Menu component to query if not authenticated (eg: there isn't a token in localStorage); I'm using in Menu component this code:

export default graphql(CURRENT_USER_QUERY)(Menu);

3) Is this the right way to go?

First, let me answer your second question: You can skip an operation using the skip query option .

export default graphql(CURRENT_USER_QUERY, {
  skip: () => !localStorage.get("auth_token"),
})(Menu);

The problem now is how to re-render this component when the local storage changes. Usually react does not listen on the local storage to trigger a re-render, instead a re-render is done using one of this three methods:

  1. The component's state changes
  2. The parent of the component re-renders (usually with new props for the child)
  3. forceUpdate is called on the component

(Note that also a change of a subscribed context will trigger a re-render but we don't want to mess around with context ;-))

You might want to go with a combination of 2. and 3. or 1. and 2. In your case it can be enough to change the route (as you do in the login function). If this does not work you can call this.forceUpdate() on the App component after Login using a callback property on <Login onLogin={() => this.forceUpdate() } /> .

EDITED

1) I just created new link https://codesandbox.io/s/0y3jl8znw

You want to fetch the user data in the componentWillReceiveProps method:

  componentWillReceiveProps() {
    this.props.client.query({query: CURRENT_USER_QUERY})
    .then((response) => {
      this.setState({ currentUser: response.data.currentUser})
    })
    .catch((e) => {
      console.log('there was an error ', e)
    })
  }

This will make the component re-render.

2) Now when we moved the query call in the component's lifecycle method we have full control over it. If you want to call the query only if you have something in localstorage you just need to wrap the query in a simple condition:

  componentWillReceiveProps() {
    if(localstora.getItem('auth_token')) {
      this.props.client.query({query: CURRENT_USER_QUERY})
      .then((response) => {
        this.setState({ currentUser: response.data.currentUser})
      })
      .catch((e) => {
        console.log('there was an error ', e)
      })
    }
  }

3) You want to store the global application state in redux store. Otherwise you will have to fetch the user info every time you need to work with it. I would recommend to define a state in you App component and store all the global values there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM