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

Для объятия его в React-Router реквизитах. Это неправильно?

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

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

export default graphql(CURRENT_USER_QUERY)(Menu);

3) разве это правильный путь?

2 10

2 ответа:

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

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

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

  1. состояние компонента изменяется
  2. родительский компонент повторно визуализируется (обычно с новыми реквизитами для ребенок)
  3. forceUpdate вызывается на компоненте

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

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

Отредактировано

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 и хранить там все глобальные значения.