#reactjs #redux #react-redux
Вопрос:
Я использую стек MERN, и у меня есть компонент, который будет создавать ресурсы для хранения в базе данных. Этот компонент имеет связанный срез redux для хранения своего состояния. Состояние включает статус запроса, отправленного на сервер для публикации создаваемого ресурса.
При первом запуске React основной компонент отображения использует функцию redux-thunk для загрузки некоторых важных ресурсов. В настоящее время он загружает статус аутентификации пользователя в срезе redux. Когда пользователь входит или выходит из системы, этот статус аутентификации изменяется.
Когда пользователь теряет свой статус аутентификации, уже загрузив защищенный компонент, сервер запрещает доступ к защищенным ресурсам и позволяет клиенту синхронизировать свой статус аутентификации. Например, пользователь входит в систему и переходит к защищенному компоненту, создающему ресурсы. Затем пользователь выходит из системы на другой вкладке. Теперь клиент по-прежнему считает, что пользователь аутентифицирован, но сервер знает, что это не так. Если клиент сделает запрос на создание нового ресурса, сервер отклонит его, и клиент синхронизирует свой статус аутентификации с сервером.
Проблема, с которой я сталкиваюсь, заключается в повторной обработке внутри среза повторной обработки, связанного с защищенным компонентом. Если сервер отклоняет запрос на создание, поскольку пользователь не прошел проверку подлинности, thunk отправляет действие для обновления статуса аутентификации пользователя.
Когда статус аутентификации пользователя изменяется, компонент ProtectedRoute немедленно отключает защищенные компоненты и монтирует компонент входа (здесь). После отключения защищенный компонент отправляет действие для сброса своего состояния восстановления.
Теперь все это происходит по мере отправки действия по сбросу аутентификации. Обещание redux-thunk разрешается после этого, и редуктор изменяет состояние redux защищенного компонента. Это делает действие сброса состояния бесполезным.
if (data.success) {
return data;
} else {
if (data.error.unauthenticated) {
// resetAuthentication action causes the protected component
// to unmount which causes it to reset associated redux state.
dispatch(resetAuthentication());
}
// thunk resolves and changes the redux state.
return rejectWithValue();
// PROBLEM: The thunk resolves after the resetAuthentication action has caused
// the protected component to reset. After it is resolved, the state is changed
// again making the reset useless.
}
По сути, это происходит:
- Клиент делает запрос на защищенные ресурсы
- Сервер отклоняет его, поскольку клиент не прошел проверку подлинности, и предоставляет клиенту возможность синхронизировать статус проверки подлинности
- Клиент синхронизирует состояние аутентификации, в результате чего пользователь удаляется от защищенного компонента, что приводит к сбросу его состояния из-за отключения
- Клиентское исправление, обрабатывающее запрос на создание, разрешает и отклоняет, вызывая изменение состояния восстановления защищенного компонента
- Действие сброса защищенного компонента при отключении становится бесполезным
Для моего приложения это означает, что в следующий раз, когда пользователь откроет защищенный компонент (после входа в систему), он сможет увидеть последствия отклоненного запроса на создание, например, кнопка для создания ресурсов отображается как красная повторная попытка вместо зеленого создания.
Я хочу, чтобы защищенные ресурсы могли правильно сбросить свое состояние, но сбой аутентификации приводит к их отключению компонентом ProtectedRoute. Я хочу найти способ решить эту проблему с минимальным шумом и дополнительным шаблонным кодом для будущих защищенных ресурсов.
Решения, которые, я думаю, сработали бы:
- Измените мой компонент ProtectedRoute, чтобы дать URL-адрес перенаправления защищенному компоненту, чтобы защищенный компонент мог перенаправлять после того, как обещание thunk будет выполнено, и состояние не будет затронуто после сброса при отключении (Требуется, чтобы я изменил реализацию ProtectedRoute из чего-то, что я нахожу повсюду. Вводит стандартный код в защищенные компоненты).
Я также считаю, что может возникнуть фундаментальная проблема в том, как я организовал компоненты и связанные с ними фрагменты redux. Пожалуйста, также предложите наилучшие методы для ситуации в целом.
Комментарии:
1. Можете ли вы объяснить, «Это делает действие состояния сброса бесполезным»? почему порядок выполнения имеет значение?
2. @thedude Действие «Сбросить состояние» должно сбросить состояние восстановления обратно в исходное состояние. Если он запускается до разрешения thunk, состояние изменяется и на самом деле не возвращается в исходное состояние. Это означает, что моя цель-сбросить состояние, чтобы, когда пользователь вернется к компоненту, не была достигнута, и пользователь увидит артефакты из разрешения thunk, такие как кнопка повтора вместо кнопки создания.
3. пожалуйста, объясните: «состояние изменилось и на самом деле не вернулось в исходное состояние». почему он не возвращается в исходное состояние, если у вас есть действие, которое сбрасывает состояние?
4. @thedude Он возвращается в исходное состояние при отправке действия сброса. Однако, поскольку обещание thunk разрешается после отправки сброса, запущенный редуктор затем изменяет состояние. Таким образом, состояние изменяется после его сброса. Это означает, что состояние больше не возвращается в исходное состояние.
5. можете ли вы объяснить, каким образом меняется состояние, когда обещание отклоняется? Пожалуйста, приведите конкретный пример
Ответ №1:
Я предложу несколько возможных подходов к вашей проблеме:
- сигнализируйте, что обновление состояния следует игнорировать с другим значением: вы можете указать другое значение
rejectWithValue
, чтобы ваш редуктор мог игнорировать обновление, если это значение указано. Так что в своем редукторе вы могли бы сделать что-то вроде:
if (data.error.unauthenticated) {
dispatch(resetAuthentication());
return rejectWithValue('cancelUpdate');
} else {
return rejectWithValue();
}
и в редукторе:
...
.addCase(postCreateArt.rejected, (state, action) => {
if (!action.payload === 'cancelUpdate') {
state.postCreateArtRequestStatus = "rejected";
}
})
- Одним из недостатков этого подхода является то, что его необходимо будет реализовать для каждого используемого вами API. Вместо
fetch
прямого использования у вас может бытьfetchApi
общий модуль, который будут использовать все ваши действия API. Этот удар мог бы управлятьunauthenticated
потоком в центральном месте.