Estoy usando Redux para la gestión del estado.
¿Cómo restablezco la tienda a su estado inicial?
Por ejemplo, supongamos que tengo dos cuentas de usuario ( u1
y u2
).
Imagine la siguiente secuencia de eventos:
El usuario
u1
inicia sesión en la aplicación y hace algo, por lo que almacenamos algunos datos en la tienda.El usuario
u1
cierra sesión.El usuario
u2
inicia sesión en la aplicación sin actualizar el navegador.
En este punto, los datos almacenados en caché se asociarán u1
y me gustaría limpiarlos.
¿Cómo puedo restablecer la tienda Redux a su estado inicial cuando el primer usuario cierra sesión?
Respuestas:
Una forma de hacerlo sería escribir un reductor de raíz en su aplicación.
El reductor raíz normalmente delegaría el manejo de la acción al reductor generado por
combineReducers()
. Sin embargo, cada vez que recibe unaUSER_LOGOUT
acción, devuelve el estado inicial nuevamente.Por ejemplo, si su reductor de raíz se ve así:
Puede cambiarle el nombre
appReducer
y escribirle una nuevarootReducer
delegación:Ahora solo tenemos que enseñarle a lo nuevo
rootReducer
a devolver el estado inicial después de laUSER_LOGOUT
acción. Como sabemos, se supone que los reductores devuelven el estado inicial cuando se los llamaundefined
como primer argumento, sin importar la acción. Usemos este hecho para despojar condicionalmente lo acumulado astate
medida que lo pasamos aappReducer
:Ahora, cuando se
USER_LOGOUT
dispare, todos los reductores se inicializarán de nuevo. También pueden devolver algo diferente de lo que hicieron inicialmente si lo desean porque también pueden verificaraction.type
.Para reiterar, el nuevo código completo se ve así:
Tenga en cuenta que no estoy mutando el estado aquí, simplemente estoy reasignando la referencia de una variable local llamada
state
antes de pasarla a otra función. La mutación de un objeto de estado sería una violación de los principios de Redux.En caso de que esté usando redux-persist , es posible que también necesite limpiar su almacenamiento. Redux-persist mantiene una copia de su estado en un motor de almacenamiento, y la copia de estado se cargará desde allí en la actualización.
Primero, debe importar el motor de almacenamiento apropiado y luego, analizar el estado antes de configurarlo
undefined
y limpiar cada clave de estado de almacenamiento.fuente
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
que se ha disparado la acción, ¿es posible obtener datos del estado desde el principio? (por ejemplo, a través de devtools)Me gustaría señalar que el comentario aceptado por Dan Abramov es correcto, excepto que experimentamos un problema extraño al usar el paquete react-router-redux junto con este enfoque. Nuestra solución fue no establecer el estado
undefined
sino utilizar el reductor de enrutamiento actual. Por lo tanto, sugeriría implementar la solución a continuación si está utilizando este paquetefuente
router
y NOrounting
combineReducers()
... si lo tuvierascombineReducers({routing: routingReducer})
, sería como se describe en la respuestaDefinir una acción:
Luego, en cada uno de sus reductores, suponiendo que esté utilizando
switch
oif-else
para manejar múltiples acciones a través de cada reductor. Voy a tomar el caso por aswitch
.De esta manera, cada vez que llame a la
RESET
acción, su reductor actualizará la tienda con el estado predeterminado.Ahora, para cerrar sesión, puede manejar lo siguiente a continuación:
Cada vez que un usuario inicia sesión, sin una actualización del navegador. La tienda siempre estará por defecto.
store.dispatch(RESET_ACTION)
solo elabora la idea. Lo más probable es que tengas un creador de acción para ese propósito. Una forma mucho mejor será que tengas unLOGOUT_ACTION
.Una vez que envíes esto
LOGOUT_ACTION
. Un middleware personalizado puede interceptar esta acción, ya sea con Redux-Saga o Redux-Thunk. Sin embargo, en ambos sentidos, puede enviar otra acción 'RESTAURAR'. De esta manera, el cierre de sesión y el restablecimiento de la tienda se realizarán de forma sincrónica y su tienda estará lista para iniciar sesión con otro usuario.fuente
undefined
guste en la otra respuesta. cuando su aplicación espera un árbol de estado y usted lo entregaundefined
, solo hay más errores y dolores de cabeza con los que lidiar que solo un árbol vacío.Solo una respuesta simplificada a la mejor respuesta:
fuente
También puede activar una acción que es manejada por todos o algunos reductores, que desea restablecer a la tienda inicial. Una acción puede desencadenar un restablecimiento de todo su estado, o solo una parte que le parezca adecuada. Creo que esta es la forma más simple y controlable de hacerlo.
fuente
Con Redux si apliqué la siguiente solución, que asume que configuré un Estado inicial en todos mis reductores (por ejemplo, {usuario: {nombre, correo electrónico}}). En muchos componentes verifico estas propiedades anidadas, por lo que con esta solución evito que mis métodos de renderización se rompan en condiciones de propiedad acopladas (por ejemplo, si state.user.email, que arrojará un error, el usuario no está definido si las soluciones mencionadas anteriormente).
fuente
ACTUALIZACIÓN NGRX4
Si está migrando a NGRX 4, puede haber notado en la guía de migración que el método de reducción de raíz para combinar sus reductores ha sido reemplazado por el método ActionReducerMap. Al principio, esta nueva forma de hacer las cosas podría hacer que restablecer el estado sea un desafío. En realidad es sencillo, pero la forma de hacerlo ha cambiado.
Esta solución está inspirada en la sección de API de meta reductores de los documentos de NGRX4 Github.
Primero, supongamos que está combinando sus reductores de esta manera usando la nueva opción ActionReducerMap de NGRX:
Ahora, supongamos que desea restablecer el estado desde app.module `
``
Y esa es básicamente una forma de lograr el mismo efecto con NGRX 4.
fuente
Combinando los enfoques de Dan, Ryan y Rob para dar cuenta del mantenimiento del
router
estado e inicializar todo lo demás en el árbol de estado, terminé con esto:fuente
Creé un componente para darle a Redux la capacidad de restablecer el estado, solo necesita usar este componente para mejorar su tienda y enviar un tipo de acción específico para activar el restablecimiento. La idea de implementación es la misma que dijo @Dan Abramov.
Github: https://github.com/wwayne/redux-reset
fuente
He creado acciones para borrar el estado. Entonces, cuando despacho un creador de acciones de cierre de sesión, también despacho acciones para borrar el estado.
Acción de registro de usuario
Creador de acciones de cierre de sesión
Reductor
No estoy seguro si esto es óptimo?
fuente
Si está utilizando acciones redux , aquí hay una solución rápida usando HOF ( función de orden superior ) para
handleActions
.Y luego use en
handleActionsEx
lugar del originalhandleActions
para manejar los reductores.La respuesta de Dan da una gran idea sobre este problema, pero no funcionó bien para mí, porque lo estoy usando
redux-persist
.Cuando se usa con
redux-persist
, simplemente pasar elundefined
estado no provocó un comportamiento persistente, por lo que sabía que tenía que eliminar manualmente el elemento del almacenamiento (React Native en mi caso, por lo tantoAsyncStorage
).o
tampoco funcionó para mí, solo me gritaron. (por ejemplo, quejarse como "Clave inesperada _persist ..." )
Entonces, de repente, pensé que todo lo que quiero es hacer que cada reductor individual devuelva su propio estado inicial cuando
RESET
se encuentra el tipo de acción. De esa manera, la persistencia se maneja naturalmente. Obviamente, sin la función de utilidad anterior (handleActionsEx
), mi código no se verá SECO (aunque es solo una línea, es decirRESET: () => initialState
), pero no podría soportarlo porque me encanta la metaprogramación.fuente
La siguiente solución funcionó para mí.
Agregué restablecer la función de estado a los meta reductores. La clave era usar
para configurar todos los reductores al estado inicial. Volver en su
undefined
lugar estaba causando errores debido al hecho de que la estructura de la tienda ha sido destruida./reducers/index.ts
app.module.ts
fuente
Desde una perspectiva de seguridad, lo más seguro que hacer cuando un registro de salida de usuario es reiniciar todo el estado persistente (ex galletas,
localStorage
,IndexedDB
,Web SQL
, etc) y hacer una actualización forzada de la página utilizandowindow.location.reload()
. Es posible que un desarrollador descuidado haya almacenado accidental o intencionalmente datos confidencialeswindow
en el DOM, etc. Eliminar todo estado persistente y actualizar el navegador es la única forma de garantizar que no se filtre información del usuario anterior al siguiente usuario.(Por supuesto, como usuario en una computadora compartida, debe usar el modo "navegación privada", cerrar la ventana del navegador usted mismo, usar la función "borrar datos de navegación", etc., pero como desarrollador no podemos esperar que todos estén siempre que diligente)
fuente
Mi solución alternativa cuando trabajo con mecanografiado, basado en la respuesta de Dan (los tipos redux hacen que sea imposible pasar
undefined
al reductor como primer argumento, por lo que guardo en caché el estado raíz inicial en una constante):fuente
La respuesta aceptada me ayudó a resolver mi caso. Sin embargo, encontré un caso en el que no todo el estado tuvo que ser borrado. Entonces, lo hice de esta manera:
Espero que esto ayude a alguien más :)
fuente
Solo una extensión de la respuesta @ dan-abramov , a veces es posible que debamos retener ciertas claves para que no se restablezcan.
fuente
Una opción rápida y fácil que funcionó para mí fue usar redux-reset . Lo cual era sencillo y también tiene algunas opciones avanzadas para aplicaciones más grandes.
Configuración en crear tienda
Despacha tu 'reset' en tu función de cierre de sesión
Espero que esto ayude
fuente
Mi opinión para evitar que Redux haga referencia a la misma variable del estado inicial:
fuente
Este enfoque es muy correcto: Destruya cualquier estado específico "NOMBRE" para ignorar y conservar a los demás.
fuente
USER_LOGOUT
en ese reductor y manejarlo allí.¿Por qué no solo usas
return module.exports.default()
;)Nota: asegúrese de establecer el valor predeterminado de la acción en
{}
y está bien porque no desea encontrar un error cuando verificaaction.type
dentro de la instrucción de cambio.fuente
Descubrí que la respuesta aceptada funcionó bien para mí, pero provocó el
no-param-reassign
error de ESLint : https://eslint.org/docs/rules/no-param-reassignAsí es como lo manejé en su lugar, asegurándome de crear una copia del estado (que, a mi entender, es lo que debe hacer Reduxy ...):
¿Pero tal vez crear una copia del estado para pasarlo a otra función reductora que crea una copia de eso es un poco demasiado complicado? Esto no se lee tan bien, pero es más directo:
fuente
Además de la respuesta de Dan Abramov, ¿no deberíamos establecer explícitamente la acción como action = {type: '@@ INIT'} junto con state = undefined. Con el tipo de acción anterior, cada reductor devuelve el estado inicial.
fuente
en el servidor, tengo una variable es: global.isSsr = true y en cada reductor, tengo un const es: initialState Para restablecer los datos en la Tienda, hago lo siguiente con cada Reductor: ejemplo con appReducer.js :
finalmente en el enrutador del servidor:
fuente
La siguiente solución me funciona.
Primero, al iniciar nuestra aplicación, el estado reductor es nuevo y nuevo con InitialState predeterminado .
Tenemos que agregar una acción que invoca la carga inicial de la aplicación para mantener el estado predeterminado .
Al cerrar sesión en la aplicación, podemos reasignar el estado predeterminado y el reductor funcionará como nuevo .
Contenedor de la aplicación principal
Reductor de la aplicación principal
Acción de llamada al cerrar sesión para restablecer el estado
¡Espero que esto resuelva tu problema!
fuente
Para restablecer el estado a su estado inicial, escribí el siguiente código:
fuente
Una cosa que la solución en la respuesta aceptada no hace es borrar el caché para los selectores parametrizados. Si tienes un selector como este:
Entonces tendrías que liberarlos al cerrar sesión de esta manera:
De lo contrario, el valor memorizado para la última llamada del selector y los valores de los últimos parámetros seguirán en la memoria.
Los ejemplos de código son de los documentos ngrx .
fuente
para mí lo que funcionó mejor es configurar el en
initialState
lugar destate
:fuente
Otra opción es:
'@@redux/INIT'
es el tipo de acción que redux se despacha automáticamente cuando ustedcreateStore
, por lo tanto, suponiendo que todos sus reductores ya tengan un valor predeterminado, esto quedaría atrapado por ellos y comenzaría su estado de nuevo. Sin embargo, podría considerarse un detalle de implementación privada de redux, por lo que el comprador tenga cuidado ...fuente
Simplemente haga que su enlace de cierre de sesión borre la sesión y actualice la página. No se necesita código adicional para su tienda. Cada vez que desee restablecer completamente el estado, una actualización de la página es una forma simple y fácilmente repetible de manejarlo.
fuente
fuente
window.location.reload();
window
, por ejemplo, react-native