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 ответа:
Во-первых, позвольте мне ответить на ваш второй вопрос: вы можете пропустить операцию, используя пропустить опцию запроса .
export default graphql(CURRENT_USER_QUERY, { skip: () => !localStorage.get("auth_token"), })(Menu);
Теперь проблема заключается в том, как повторно отобразить этот компонент при изменении локального хранилища. Обычно react не прослушивает локальное хранилище, чтобы вызвать повторную визуализацию, вместо этого повторная визуализация выполняется с помощью одного из следующих трех методов:
- состояние компонента изменяется
- родительский компонент повторно визуализируется (обычно с новыми реквизитами для ребенок)
- 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
и хранить там все глобальные значения.