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