React, Apollo 2, GraphQL, Аутентификация. Как повторно выполнить компонент после входа в систему

У меня есть этот код: https://codesandbox.io/s/507w9qxrrl

Я не понимаю:

1) Как перерисовать() Menu после:

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

Если я вхожу в систему(), я ожидаю, что мой компонент Menu будет перерисовывать() сам. Но ничего. Только если я нажимаю ссылку "Домой", она повторно отображает(). Я подозреваю, потому что я использую это для рендеринга:

<Route component={Menu} />

чтобы охватить его в реквизитах ретранслятора. Это неправильно?

Плюс, если проверить this.props меню после login(), я вижу loading: true навсегда. Почему?

2) Как предотвратить компонент Menu для запроса, если не аутентифицирован (например: в локальном хранилище нет токена); Я использую в компоненте Menu этот код:

export default graphql(CURRENT_USER_QUERY)(Menu);

3) Правильно ли это?

Ответ 1

Во-первых, позвольте мне ответить на ваш второй вопрос: вы можете пропустить операцию, используя опцию пропустить запрос.

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

Теперь проблема заключается в том, как перерисовать этот компонент при изменении локального хранилища. Обычно реакция не прослушивает локальное хранилище, чтобы вызвать повторную визуализацию, вместо этого повторная визуализация выполняется с использованием одного из этих трех методов:

  • Состояние компонента изменяет
  • Родитель компонента повторно отображает (обычно с новыми реквизитами для дочернего элемента)
  • forceUpdate вызывается на компоненте

(Обратите внимание, что также изменение подписанного контекста вызовет повторную визуализацию, но мы не хотим вмешиваться в контекст; -))

Возможно, вы захотите пойти с комбинацией 2. и 3. или 1. и 2. В вашем случае этого может быть достаточно, чтобы изменить маршрут (как и в функции входа). Если это не сработает, вы можете вызвать this.forceUpdate() в компоненте App после входа в систему, используя свойство обратного вызова на <Login onLogin={() => this.forceUpdate() } />.

Ответ 2

EDITED

1) Я только что создал новую ссылку https://codesandbox.io/s/0y3jl8znw

Вы хотите получить пользовательские данные в методе componentWillReceiveProps:

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

Это сделает повторную визуализацию компонента.

2) Теперь, когда мы переместили вызов запроса в метод жизненного цикла компонента, мы полностью контролируем его. Если вы хотите вызвать запрос, только если у вас есть что-то в localstorage, вам просто нужно обернуть запрос в простом состоянии:

  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). Вы хотите сохранить глобальное состояние приложения в магазине redux. В противном случае вам придется получать информацию о пользователе каждый раз, когда вам нужно работать с ним. Я бы рекомендовал определить state в вашем компоненте App и сохранить там все глобальные значения.