Как сбросить состояние Redux-хранилища?
Я использую Redux для управления состоянием приложения. Как можно сбросить хранилище до его исходного состояния?
Допустим, у меня есть два аккаунта пользователей (u1 и u2). Рассмотрим следующую последовательность событий:
- Пользователь u1 вошел в приложение и выполнил некоторые действия, в результате чего мы кэшируем данные в store.
- Пользователь u1 выходит из приложения.
- Пользователь u2 входит в приложение без обновления браузера.
На этом этапе кэшированные данные будут ассоциированы с пользователем u1, и мне нужно их очистить.
Как сбросить хранилище Redux до его исходного состояния при выходе первого пользователя?
5 ответ(ов)
Чтобы определить действие RESET
, воспользуйтесь следующим кодом:
const RESET_ACTION = {
type: "RESET"
}
Затем в каждом из ваших редьюсеров, предположим, что вы используете switch
или if-else
для обработки нескольких действий в каждом редьюсере, рассмотрим случай с switch
.
const INITIAL_STATE = {
loggedIn: true
}
const randomReducer = (state = INITIAL_STATE, action) => {
switch(action.type) {
case 'SOME_ACTION_TYPE':
// обработка действия SOME_ACTION_TYPE
case "RESET":
return INITIAL_STATE; // всегда возвращайте начальное состояние
default:
return state;
}
}
Таким образом, каждый раз, когда вы вызываете действие RESET
, ваш редьюсер обновит хранилище до начального состояния.
Теперь, для обработки выхода из системы, вы можете сделать это следующим образом:
const logoutHandler = () => {
store.dispatch(RESET_ACTION);
// Кроме того, можно добавить пользовательскую логику для остальных шагов выхода
}
Каждый раз, когда пользователь входит в систему, без обновления браузера. Хранилище всегда будет находиться в начальном состоянии.
store.dispatch(RESET_ACTION)
просто подчеркивает идею. Скорее всего, у вас будет создатель действий для этой цели. Более уместный вариант — это наличие действия LOGOUT_ACTION
.
После того, как вы вызовете это LOGOUT_ACTION
, пользовательская промежуточная программа может перехватить это действие, используя Redux-Saga или Redux-Thunk. В обоих случаях вы можете вызвать другое действие RESET
. Таким образом, выход из системы и сброс произойдут синхронно, и ваше хранилище будет готово для входа другого пользователя.
Чтобы создать корневой редюсер в Redux Toolkit с использованием TypeScript, вы можете воспользоваться следующим примером кода:
import { combineReducers, AnyAction } from '@reduxjs/toolkit';
import { logout } from './yourActions'; // импортируйте ваше действие
const appReducer = combineReducers({
/* редюсеры верхнего уровня вашего приложения */
});
const rootReducer = (
state: ReturnType<typeof appReducer>,
action: AnyAction
) => {
// Если вы используете Redux Toolkit, вы можете импортировать ваше действие и использовать его свойство type вместо литерального определения действия
if (action.type === logout.type) {
return appReducer(undefined, { type: undefined });
}
return appReducer(state, action);
};
export default rootReducer;
В этом примере мы определяем appReducer
, который комбинирует все редюсеры приложения. Затем создаем rootReducer
, который обрабатывает действие logout
. Если действие имеет тип logout
, мы сбрасываем состояние редюсера до исходного состояния, передавая undefined
в качестве состояния. В противном случае мы просто передаем текущее состояние и действие в appReducer
.
Обратите внимание, что использование logout.type
обеспечивает типизацию, что является преимуществом при использовании TypeScript.
С точки зрения безопасности, наиболее надежным решением при выходе пользователя из системы является сброс всех постоянных состояний (например, куки, localStorage
, IndexedDB
, Web SQL
и т.д.) и принудительное обновление страницы с помощью window.location.reload()
. Есть вероятность, что неаккуратный разработчик случайно или намеренно сохранил какие-либо конфиденциальные данные в window
, в DOM и так далее. Удаление всех постоянных состояний и обновление браузера — это единственный способ гарантировать, что информация от предыдущего пользователя не будет утечена следующему.
(Разумеется, если вы используете общий компьютер, вам следует использовать режим «инкогнито», самостоятельно закрыть окно браузера, воспользоваться функцией «очистка данных браузера» и так далее, но как разработчики, мы не можем ожидать от всех, что они всегда будут столь осторожны).
Ваша функция редюсера для сброса состояния выглядит довольно неплохо. Ниже приведен перевод на русский язык в стиле ответа на вопрос на StackOverflow:
Вы можете создать действие, которое будет обрабатываться всеми или некоторыми редюсерами, чтобы сбросить состояние до начального значения. Одно действие может триггерить сброс всего состояния, или только его части, в зависимости от ваших нужд. Я считаю, что это самый простой и контролируемый способ сделать это.
Ваш код уже делает шаг в этом направлении. Вот небольшой пример, как можно структурировать редюсер для сброса состояния:
const reducer = (state = initialState, { type, payload }) => {
switch (type) {
case RESET_STORE: {
return initialState; // Сбрасываем состояние до начального
}
// Здесь можно добавить дополнительные обработчики действий
default:
return state; // Возвращаем текущее состояние по умолчанию
}
}
Таким образом, когда ваше действие RESET_STORE
будет вызвано, редюсер сбросит состояние до initialState
. Вы также можете добавлять дополнительные случаи в switch
, чтобы обработать другие действия при необходимости. Надеюсь, это поможет вам в реализации!
Ваше решение выглядит довольно хорошо для управления состоянием в приложении Redux. Вы правы в том, что правильная настройка initialState
может предотвратить проблемы с доступом к вложенным свойствам. Вы можете использовать этот код, чтобы гарантировать, что ваши компоненты не будут ломаться из-за ошибок доступа к неопределенным свойствам, например, когда вы пытаетесь получить state.user.email
.
Ваши изменения в rootReducer
также помогают сбросить состояние обратно к initialState
при выполнении действия LOG_OUT
. Это хорошая практика, так как она позволяет вам начинать с чистого состояния после выхода пользователя.
Вот краткое объяснение вашего решения:
combineReducers
объединяет редюсеры в один, создаваяappReducer
.initialState
устанавливается как результат вызоваappReducer
с пустыми объектами, что гарантирует, что у вас есть начальные значения для всех редюсеров.- В
rootReducer
вы проверяете действиеLOG_OUT
, и если оно срабатывает, состояние сбрасывается доinitialState
. - Затем вы возвращаете новое состояние, передавая его в
appReducer
.
С помощью этой структуры вы уменьшаете вероятность возникновения ошибок при доступе к свойствам состояния и обеспечиваете правильное управление состоянием при выходе пользователя из системы.
Если у вас возникнут дополнительные вопросы или потребуется помощь с улучшением этого решения, не стесняйтесь спрашивать!
Как отправить действие Redux с таймаутом?
В чем разница между String.slice и String.substring?
Проверка соответствия строки регулярному выражению в JS
Существует ли ссылка на "последнюю" библиотеку jQuery в Google APIs?
Как создать диалог с кнопками "Ок" и "Отмена"