Я использую Redux для управления состоянием.
Как мне сбросить магазин в исходное состояние?
Например, допустим, у меня есть две учетные записи ( u1
и u2
).
Представьте себе следующую последовательность событий:
Пользователь
u1
входит в приложение и что-то делает, поэтому мы кешируем некоторые данные в магазине.Пользователь
u1
выходит из системы.Пользователь
u2
входит в приложение без обновления браузера.
На этом этапе кэшированные данные будут связаны u1
, и я бы хотел их очистить.
Как я могу сбросить хранилище Redux в исходное состояние, когда первый пользователь выходит из системы?
Ответы:
Один из способов сделать это - написать корневой редуктор в вашем приложении.
Корневой редуктор обычно делегирует обработку действия редуктору, сгенерированному с помощью
combineReducers()
. Однако всякий раз, когда он получаетUSER_LOGOUT
действие, он снова возвращает исходное состояние.Например, если ваш корневой редуктор выглядел так:
Вы можете переименовать его
appReducer
и написать новоеrootReducer
делегирование:Теперь нам просто нужно научить новое
rootReducer
возвращать исходное состояние послеUSER_LOGOUT
действия. Как мы знаем, редукторы должны возвращать начальное состояние, когда они вызываютсяundefined
в качестве первого аргумента, независимо от действия. Давайте использовать этот факт для условного удаления накопленногоstate
при передачеappReducer
:Теперь при каждом
USER_LOGOUT
запуске все редукторы будут инициализироваться заново. Они также могут вернуть что-то отличное от первоначального, если захотят, потому что они тоже могут проверитьaction.type
.Повторюсь, полный новый код выглядит так:
Обратите внимание, что я не изменяю здесь состояние, я просто переназначаю ссылку на локальную переменную, вызываемую
state
перед передачей ее другой функции. Мутирование состояния объекта было бы нарушением принципов Redux.В случае, если вы используете redux-persist , вам также может понадобиться очистить хранилище. Redux-persist хранит копию вашего состояния в хранилище, и копия состояния будет загружена оттуда при обновлении.
Сначала необходимо импортировать соответствующий механизм хранения, а затем проанализировать состояние, прежде чем устанавливать его,
undefined
и очистить каждый ключ состояния хранения.источник
case 'CLEAR_DATA': return initialState
export const createRootReducer = asyncReducers => { const appReducer = combineReducers({ myReducer ...asyncReducers }); return (state, action) => { if (action.type === 'LOGOUT_USER') { state = undefined; } return appReducer(state, action); } };
if (action.type === 'RESET') return action.stateFromLocalStorage
USER_LOGOUT
действие было запущено, возможно ли получить данные о состоянии от ранее? (например, через devtools)Я хотел бы отметить, что принятый комментарий Дана Абрамова является правильным, за исключением того, что мы столкнулись со странной проблемой при использовании пакетаact-router-redux вместе с этим подходом. Мы решили не устанавливать состояние,
undefined
а использовать текущий редуктор маршрутизации. Поэтому я бы предложил реализовать решение ниже, если вы используете этот пакетисточник
router
и НЕrounting
combineReducers()
..... если бы у вас было,combineReducers({routing: routingReducer})
как было бы описано в ответеОпределите действие:
Затем в каждом из ваших редукторов предполагается, что вы используете
switch
илиif-else
для обработки нескольких действий через каждый редуктор. Я собираюсь взять дело заswitch
.Таким образом, всякий раз, когда вы вызываете
RESET
действие, вы обновляете хранилище с состоянием по умолчанию.Теперь для выхода из системы вы можете выполнить следующее:
Каждый раз, когда пользователь входит в систему, без обновления браузера. Магазин всегда будет по умолчанию.
store.dispatch(RESET_ACTION)
просто развивает идею. Скорее всего, у вас будет создатель действий для этой цели. Намного лучше будет то, что у вас естьLOGOUT_ACTION
.Как только вы отправите это
LOGOUT_ACTION
. Пользовательское промежуточное ПО может затем перехватить это действие либо с Redux-Saga, либо с Redux-Thunk. Однако в обоих случаях вы можете отправить другое действие «СБРОС». Таким образом, выход из магазина и сброс будут происходить синхронно, и ваш магазин будет готов для входа другого пользователя.источник
undefined
как в другом ответе. когда ваше приложение ожидает дерево состояний и вы даете егоundefined
вместо этого, есть только больше ошибок и головных болей, чем просто пустое дерево.Просто упрощенный ответ на лучший ответ:
источник
Вы также можете запустить действие, которое обрабатывается всеми или некоторыми редукторами, которые вы хотите сбросить в исходное хранилище. Одно действие может вызвать сброс к вашему состоянию в целом или просто к его части, которая кажется вам подходящей. Я считаю, что это самый простой и самый контролируемый способ сделать это.
источник
С Redux if применили следующее решение, которое предполагает, что я установил initialState во всех моих редукторах (например, {user: {name, email}}). Во многих компонентах я проверяю эти вложенные свойства, поэтому с помощью этого исправления я предотвращаю сбои моих методов рендеринга в условиях связанных свойств (например, если state.user.email, который выдаст ошибку, не определен пользователем, если упомянутые выше решения).
источник
ОБНОВЛЕНИЕ NGRX4
Если вы переходите на NGRX 4, вы, возможно, заметили из руководства по миграции, что метод rootreducer для объединения ваших редукторов был заменен методом ActionReducerMap. Во-первых, этот новый способ действий может сделать сброс состояния вызовом. Это на самом деле просто, но способ сделать это изменился.
Это решение вдохновлено разделом API метаредукторов документации NGRX4 Github.
Во-первых, предположим, что вы комбинируете свои редукторы, как это, используя новую опцию ActionGReducerMap в NGRX:
Теперь предположим, что вы хотите сбросить состояние из app.module
`
И это в основном один из способов добиться того же эффекта с NGRX 4.
источник
Комбинируя подходы Дэна, Райана и Роба для учета
router
состояния и инициализации всего остального в дереве состояний, я получил следующее:источник
Я создал компонент, чтобы дать Redux возможность сброса состояния, вам просто нужно использовать этот компонент для улучшения вашего хранилища и отправки определенного action.type для запуска сброса. Мысль о реализации такая же, как и то, что сказал @Dan Abramov.
Github: https://github.com/wwayne/redux-reset
источник
Я создал действия, чтобы очистить государство. Поэтому, когда я отправляю создателя действий выхода из системы, я также отправляю действия для очистки состояния.
Действие записи пользователя
Выйти из создателя действий
редуктор
Я не уверен, что это оптимально?
источник
Если вы используете redux-действия , вот быстрый обходной путь, используя HOF ( функцию более высокого порядка ) для
handleActions
.А потом использовать
handleActionsEx
вместо оригиналаhandleActions
для обработки редукторов.Ответ Дэна дает отличное представление об этой проблеме, но она не сработала для меня, потому что я использую
redux-persist
.При использовании с
redux-persist
простым передачейundefined
состояния не запускалось постоянное поведение, поэтому я знал, что должен был вручную удалить элемент из хранилища (таким образом, в моем случае это React NativeAsyncStorage
).или
у меня тоже не получилось - они просто наорали на меня. (например, жалоба типа «Неожиданный ключ _persist ...» )
Затем я внезапно подумал, что все, что я хочу, это просто заставить каждый отдельный редуктор возвращать свое собственное начальное состояние при
RESET
обнаружении типа действия. Таким образом, упорство обрабатывается естественно. Очевидно, что без использования служебной функции (handleActionsEx
) мой код не будет выглядеть СУХИМ (хотя это всего лишь одна строка, т.е.RESET: () => initialState
), но я не мог этого вынести, потому что я люблю метапрограммирование.источник
Следующее решение сработало для меня.
Я добавил функцию сброса состояния в мета редукторы. Ключ должен был использовать
установить все редукторы в исходное состояние. Возврат
undefined
взамен вызывал ошибки из-за того, что структура магазина была разрушена./reducers/index.ts
app.module.ts
источник
С точкой зрения безопасности, безопаснее всего делать , когда выход из системы , чтобы сбросить все постоянное состояние (бывшее печенье,
localStorage
,IndexedDB
,Web SQL
и т.д.) и сделать жесткое обновление страницы с помощьюwindow.location.reload()
. Возможно, неаккуратный разработчик случайно или намеренно сохранил некоторые конфиденциальные данныеwindow
в DOM и т. Д. Сброс всех постоянных состояний и обновление браузера - единственный способ гарантировать, что информация от предыдущего пользователя не будет передана следующему пользователю.(Конечно, как пользователь на компьютере с общим доступом, вы должны использовать режим «частного просмотра», самостоятельно закрывать окно браузера, использовать функцию «очистки данных просмотра» и т. Д., Но как разработчик мы не можем ожидать, что все всегда будут прилежный)
источник
Мой обходной путь при работе с машинописью, основанной на ответе Дэна (избыточные типизации делают невозможным переход
undefined
к редуктору в качестве первого аргумента, поэтому я кеширую начальное корневое состояние в константу):источник
Принятый ответ помог мне решить мой случай. Однако я столкнулся со случаем, когда необходимо очистить не все состояние. Итак - я сделал это так:
Надеюсь, это поможет кому-то еще :)
источник
Просто расширение ответа @ dan-abramov , иногда нам может потребоваться сохранить некоторые ключи от сброса.
источник
Быстрая и простая опция, которая работала для меня, использовала Redux-Reset . Который был прост и также имеет некоторые дополнительные параметры, для больших приложений.
Настройка в магазине создания
Отправьте ваш «сброс» в функции выхода из системы
Надеюсь это поможет
источник
Мое предположение, чтобы Redux не ссылался на ту же переменную исходного состояния:
источник
Этот подход очень правильный: уничтожить любое конкретное состояние «ИМЯ», чтобы игнорировать и удерживать других.
источник
USER_LOGOUT
этот редуктор и обработать его там.почему бы тебе просто не использовать
return module.exports.default()
;)Примечание: убедитесь, что вы установили значение по умолчанию для действия,
{}
и у вас все в порядке, потому что вы не хотите, чтобыaction.type
произошла ошибка при проверке внутри оператора switch.источник
Я обнаружил, что принятый ответ хорошо работает для меня, но он вызвал
no-param-reassign
ошибку ESLint - https://eslint.org/docs/rules/no-param-reassignВот как я справился с этим, убедившись, что создал копию состояния (что, на мой взгляд, нужно сделать в Reduxy ...):
Но, может быть, создание копии состояния для простой передачи ее в другую функцию-редуктор, которая создает копию, которая немного сложнее? Это выглядит не так хорошо, но более конкретно:
источник
В дополнение к ответу Дана Абрамова, не должны ли мы явно установить действие как action = {type: '@@ INIT'} рядом с state = undefined. При указанном выше типе действия каждый редуктор возвращает исходное состояние.
источник
на сервере у меня есть переменная: global.isSsr = true, и в каждом редукторе у меня есть const: initialState Чтобы сбросить данные в хранилище, я делаю следующее с каждым редуктором: пример с appReducer.js :
наконец на маршрутизаторе сервера:
источник
Следующее решение работает для меня.
Сначала при запуске нашего приложения состояние редуктора является новым и новым по умолчанию InitialState .
Мы должны добавить действие, которое вызывает начальную загрузку приложения для сохранения состояния по умолчанию .
При выходе из приложения мы можем просто переназначить состояние по умолчанию, и редуктор будет работать как новый .
Основной APP Контейнер
Главный APP Редуктор
При выходе из системы вызывается действие для сброса состояния
Надеюсь, это решит вашу проблему!
источник
Для того чтобы сбросить состояние до его начального состояния, я написал следующий код:
источник
Единственное, что решение в принятом ответе не делает, это очистить кэш для параметризованных селекторов. Если у вас есть такой селектор:
Тогда вам нужно будет выпустить их при выходе из системы следующим образом:
В противном случае запомненное значение для последнего вызова селектора и значения последних параметров останутся в памяти.
Примеры кода взяты из документации ngrx .
источник
для меня лучше всего было бы установить
initialState
вместоstate
:источник
Другим вариантом является:
'@@redux/INIT'
это тип действия, который при вашей редукции отправляет автоматическиcreateStore
, так что, если у ваших редукторов уже есть значение по умолчанию, они будут перехвачены и начнут ваше состояние заново. Впрочем, это можно считать частной реализацией избыточности, так что покупатель остерегается ...источник
Просто очистите сеанс по ссылке на выход из системы и обновите страницу. Для вашего магазина не требуется дополнительный код. Каждый раз, когда вы хотите полностью сбросить состояние, обновление страницы - это простой и легко повторяемый способ справиться с этим.
источник
источник
window.location.reload();
window
, например,