¿Cómo restablecer el estado de una tienda Redux?

455

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 ( u1y u2).
Imagine la siguiente secuencia de eventos:

  1. El usuario u1inicia sesión en la aplicación y hace algo, por lo que almacenamos algunos datos en la tienda.

  2. El usuario u1cierra sesión.

  3. El usuario u2inicia sesión en la aplicación sin actualizar el navegador.

En este punto, los datos almacenados en caché se asociarán u1y me gustaría limpiarlos.

¿Cómo puedo restablecer la tienda Redux a su estado inicial cuando el primer usuario cierra sesión?

xyz
fuente
8
Probablemente sea mejor borrar el estado al cerrar sesión (desde una perspectiva de seguridad)
Clarkie

Respuestas:

1033

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 una USER_LOGOUTacción, devuelve el estado inicial nuevamente.

Por ejemplo, si su reductor de raíz se ve así:

const rootReducer = combineReducers({
  /* your app’s top-level reducers */
})

Puede cambiarle el nombre appReducery escribirle una nueva rootReducerdelegación:

const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  return appReducer(state, action)
}

Ahora solo tenemos que enseñarle a lo nuevo rootReducera devolver el estado inicial después de la USER_LOGOUTacción. Como sabemos, se supone que los reductores devuelven el estado inicial cuando se los llama undefinedcomo primer argumento, sin importar la acción. Usemos este hecho para despojar condicionalmente lo acumulado a statemedida que lo pasamos a appReducer:

 const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    state = undefined
  }

  return appReducer(state, action)
}

Ahora, cuando se USER_LOGOUTdispare, 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 verificar action.type.

Para reiterar, el nuevo código completo se ve así:

const appReducer = combineReducers({
  /* your app’s top-level reducers */
})

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    state = undefined
  }

  return appReducer(state, action)
}

Tenga en cuenta que no estoy mutando el estado aquí, simplemente estoy reasignando la referencia de una variable local llamada stateantes 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 undefinedy limpiar cada clave de estado de almacenamiento.

const rootReducer = (state, action) => {
    if (action.type === SIGNOUT_REQUEST) {
        // for all keys defined in your persistConfig(s)
        storage.removeItem('persist:root')
        // storage.removeItem('persist:otherKey')

        state = undefined;
    }
    return appReducer(state, action);
};
Dan Abramov
fuente
15
Tengo curiosidad, Dan, ¿podrías hacer algo así en tu reductor? con CLEAR_DATA siendo la acción. case 'CLEAR_DATA': return initialState
HussienK
66
@HussienK que funcionaría pero no en el estado para cada reductor.
Cory Danielson
12
Aquí hay una versión donde combina dinámicamente los reductores en caso de que use reductores asíncronos:export const createRootReducer = asyncReducers => { const appReducer = combineReducers({ myReducer ...asyncReducers }); return (state, action) => { if (action.type === 'LOGOUT_USER') { state = undefined; } return appReducer(state, action); } };
Ivo Sabev
2
if (action.type === 'RESET') return action.stateFromLocalStorage
Dan Abramov
3
¿Este enfoque aclara completamente el estado y toda su historia? Estoy pensando desde una perspectiva de seguridad: si esto se ha implementado, una vez USER_LOGOUTque se ha disparado la acción, ¿es posible obtener datos del estado desde el principio? (por ejemplo, a través de devtools)
AlexKempton
81

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 undefinedsino utilizar el reductor de enrutamiento actual. Por lo tanto, sugeriría implementar la solución a continuación si está utilizando este paquete

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    const { routing } = state
    state = { routing } 
  }
  return appReducer(state, action)
}
Ryan Irilli
fuente
19
Creo que la conclusión aquí es que es posible que no desee borrar todo el árbol de estado al cerrar sesión: el enfoque funciona igualmente bien en el reductor de raíz de cualquier subárbol, por lo que puede ser más claro aplicar esta técnica solo en los reductores de raíz del subárbol (s) que no desea borrar, en vez de seleccionar 'especial' a los niños no clara en el reductor de la raíz de todo el árbol, como este
davnicwil
1
Creo que estoy experimentando estos problemas a los que te estás refiriendo en este momento (cuando al cerrar sesión establecerá la ruta en la ruta correcta pero se cargaría un componente completamente diferente) implementé algo similar al tuyo para solucionarlo, pero creo que algo con inmutable js está concentrando esto. Terminé creando un reductor principal que tiene acción RESET-STATE, y heredé de ese reductor para evitar tocar el enrutamiento por completo
Neta Meta
Estaba experimentando problemas similares, esto lo ha solucionado. Gracias.
Lloyd Watkin
3
Tenga en cuenta que con react-redux-router, la propiedad es routery NOrounting
Mrchief
2
@Mrchief, depende de cómo lo definiste en tu combineReducers()... si lo tuvieras combineReducers({routing: routingReducer}), sería como se describe en la respuesta
Ben Lonsdale
40

Definir una acción:

const RESET_ACTION = {
  type: "RESET"
}

Luego, en cada uno de sus reductores, suponiendo que esté utilizando switcho if-elsepara manejar múltiples acciones a través de cada reductor. Voy a tomar el caso por a switch.

const INITIAL_STATE = {
  loggedIn: true
}

const randomReducer = (state=INITIAL_STATE, action) {
  switch(action.type) {
    case 'SOME_ACTION_TYPE':

       //do something with it

    case "RESET":

      return INITIAL_STATE; //Always return the initial state

   default: 
      return state; 
  }
}

De esta manera, cada vez que llame a la RESETacción, su reductor actualizará la tienda con el estado predeterminado.

Ahora, para cerrar sesión, puede manejar lo siguiente a continuación:

const logoutHandler = () => {
    store.dispatch(RESET_ACTION)
    // Also the custom logic like for the rest of the logout handler
}

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 un LOGOUT_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.

nirbhaygp
fuente
1
Creo que este es el mejor enfoque que simplemente establecer el estado para que me undefinedguste en la otra respuesta. cuando su aplicación espera un árbol de estado y usted lo entrega undefined, solo hay más errores y dolores de cabeza con los que lidiar que solo un árbol vacío.
worc
3
@worc El estado en realidad no estará indefinido, porque los reductores devuelven estado inicial cuando reciben un estado indefinido
Guillaume
3
@worc piensa que con este enfoque, cada vez que alguien cree un nuevo reductor, deberá recordar agregar el caso de reinicio.
Francute
1
Definitivamente he cambiado de opinión al respecto, por ambas razones, además de la idea de que RESET_ACTION es una acción . para empezar, realmente no pertenece al reductor.
worc
1
Este es definitivamente el enfoque correcto. Establecer el estado en cualquier cosa que no sea el Estado inicial solo está pidiendo problemas
Sebastian Serrano
15

Solo una respuesta simplificada a la mejor respuesta:

const rootReducer = combineReducers({
    auth: authReducer,
    ...formReducers,
    routing
});


export default (state, action) =>
  rootReducer(action.type === 'USER_LOGOUT' ? undefined : state, action);
Matt Carlotta
fuente
esto está funcionando gracias, era de la respuesta de Dan pero no puedo entenderlo.
Aljohn Yamaro
14
 const reducer = (state = initialState, { type, payload }) => {

   switch (type) {
      case RESET_STORE: {
        state = initialState
      }
        break
   }

   return state
 }

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.

Daniel petrov
fuente
10

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).

const appReducer = combineReducers({
  tabs,
  user
})

const initialState = appReducer({}, {})

const rootReducer = (state, action) => {
  if (action.type === 'LOG_OUT') {
    state = initialState
  }

  return appReducer(state, action)
}
Rob Moorman
fuente
7

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:

//index.reducer.ts
export const reducers: ActionReducerMap<State> = {
    auth: fromAuth.reducer,
    layout: fromLayout.reducer,
    users: fromUsers.reducer,
    networks: fromNetworks.reducer,
    routingDisplay: fromRoutingDisplay.reducer,
    routing: fromRouting.reducer,
    routes: fromRoutes.reducer,
    routesFilter: fromRoutesFilter.reducer,
    params: fromParams.reducer
}

Ahora, supongamos que desea restablecer el estado desde app.module `

//app.module.ts
import { IndexReducer } from './index.reducer';
import { StoreModule, ActionReducer, MetaReducer } from '@ngrx/store';
...
export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
    return function(state, action) {

      switch (action.type) {
          case fromAuth.LOGOUT:
            console.log("logout action");
            state = undefined;
      }

      return reducer(state, action);
    }
  }

  export const metaReducers: MetaReducer<any>[] = [debug];

  @NgModule({
    imports: [
        ...
        StoreModule.forRoot(reducers, { metaReducers}),
        ...
    ]
})

export class AppModule { }

``

Y esa es básicamente una forma de lograr el mismo efecto con NGRX 4.

Tyler Brown
fuente
5

Combinando los enfoques de Dan, Ryan y Rob para dar cuenta del mantenimiento del routerestado e inicializar todo lo demás en el árbol de estado, terminé con esto:

const rootReducer = (state, action) => appReducer(action.type === LOGOUT ? {
    ...appReducer({}, {}),
    router: state && state.router || {}
  } : state, action);
Andy_D
fuente
4

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

Wwayne
fuente
4

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

export const clearUserRecord = () => ({
  type: CLEAR_USER_RECORD
});

Creador de acciones de cierre de sesión

export const logoutUser = () => {
  return dispatch => {
    dispatch(requestLogout())
    dispatch(receiveLogout())
    localStorage.removeItem('auth_token')
    dispatch({ type: 'CLEAR_USER_RECORD' })
  }
};

Reductor

const userRecords = (state = {isFetching: false,
  userRecord: [], message: ''}, action) => {
  switch (action.type) {
    case REQUEST_USER_RECORD:
    return { ...state,
      isFetching: true}
    case RECEIVE_USER_RECORD:
    return { ...state,
      isFetching: false,
      userRecord: action.user_record}
    case USER_RECORD_ERROR:
    return { ...state,
      isFetching: false,
      message: action.message}
    case CLEAR_USER_RECORD:
    return {...state,
      isFetching: false,
      message: '',
      userRecord: []}
    default:
      return state
  }
};

No estoy seguro si esto es óptimo?

Navinesh Chand
fuente
2

Si está utilizando acciones redux , aquí hay una solución rápida usando HOF ( función de orden superior ) para handleActions.

import { handleActions } from 'redux-actions';

export function handleActionsEx(reducer, initialState) {
  const enhancedReducer = {
    ...reducer,
    RESET: () => initialState
  };
  return handleActions(enhancedReducer, initialState);
}

Y luego use en handleActionsExlugar del original handleActionspara 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 el undefinedestado 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 tanto AsyncStorage).

await AsyncStorage.removeItem('persist:root');

o

await persistor.flush(); // or await persistor.purge();

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 RESETse 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 decir RESET: () => initialState), pero no podría soportarlo porque me encanta la metaprogramación.

elquimista
fuente
2

La siguiente solución funcionó para mí.

Agregué restablecer la función de estado a los meta reductores. La clave era usar

return reducer(undefined, action);

para configurar todos los reductores al estado inicial. Volver en su undefinedlugar estaba causando errores debido al hecho de que la estructura de la tienda ha sido destruida.

/reducers/index.ts

export function resetState(reducer: ActionReducer<State>): ActionReducer<State> {
  return function (state: State, action: Action): State {

    switch (action.type) {
      case AuthActionTypes.Logout: {
        return reducer(undefined, action);
      }
      default: {
        return reducer(state, action);
      }
    }
  };
}

export const metaReducers: MetaReducer<State>[] = [ resetState ];

app.module.ts

import { StoreModule } from '@ngrx/store';
import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, { metaReducers })
  ]
})
export class AppModule {}
Pan Piotr
fuente
2

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 utilizando window.location.reload(). Es posible que un desarrollador descuidado haya almacenado accidental o intencionalmente datos confidenciales windowen 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)

tlrobinson
fuente
1
¿Por qué la gente ha rechazado esto? Cuando realiza un nuevo estado redux, con contenido vacío, básicamente todavía tiene los estados anteriores en la memoria, y en teoría podría acceder a los datos de ellos. ¡Actualizar el navegador ES tu apuesta más segura!
Wilhelm Sorban
2

Mi solución alternativa cuando trabajo con mecanografiado, basado en la respuesta de Dan (los tipos redux hacen que sea imposible pasar undefinedal reductor como primer argumento, por lo que guardo en caché el estado raíz inicial en una constante):

// store

export const store: Store<IStoreState> = createStore(
  rootReducer,
  storeEnhacer,
)

export const initialRootState = {
  ...store.getState(),
}

// root reducer

const appReducer = combineReducers<IStoreState>(reducers)

export const rootReducer = (state: IStoreState, action: IAction<any>) => {
  if (action.type === "USER_LOGOUT") {
    return appReducer(initialRootState, action)
  }

  return appReducer(state, action)
}


// auth service

class Auth {
  ...

  logout() {
    store.dispatch({type: "USER_LOGOUT"})
  }
}
Jacka
fuente
2

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:

const combinedReducer = combineReducers({
    // my reducers 
});

const rootReducer = (state, action) => {
    if (action.type === RESET_REDUX_STATE) {
        // clear everything but keep the stuff we want to be preserved ..
        delete state.something;
        delete state.anotherThing;
    }
    return combinedReducer(state, action);
}

export default rootReducer;

Espero que esto ayude a alguien más :)

pesho hristov
fuente
¿Qué sucede si tengo más de 10 estados pero quiero restablecer el estado de un solo reductor?
Paul
1

Solo una extensión de la respuesta @ dan-abramov , a veces es posible que debamos retener ciertas claves para que no se restablezcan.

const retainKeys = ['appConfig'];

const rootReducer = (state, action) => {
  if (action.type === 'LOGOUT_USER_SUCCESS' && state) {
    state = !isEmpty(retainKeys) ? pick(state, retainKeys) : undefined;
  }

  return appReducer(state, action);
};
gsaandy
fuente
1

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

import reduxReset from 'redux-reset'
...
const enHanceCreateStore = compose(
applyMiddleware(...),
reduxReset()  // Will use 'RESET' as default action.type to trigger reset
)(createStore)
const store = enHanceCreateStore(reducers)

Despacha tu 'reset' en tu función de cierre de sesión

store.dispatch({
type: 'RESET'
})

Espero que esto ayude

Munei Nengwenani
fuente
1

Mi opinión para evitar que Redux haga referencia a la misma variable del estado inicial:

// write the default state as a function
const defaultOptionsState = () => ({
  option1: '',
  option2: 42,
});

const initialState = {
  options: defaultOptionsState() // invoke it in your initial state
};

export default (state = initialState, action) => {

  switch (action.type) {

    case RESET_OPTIONS:
    return {
      ...state,
      options: defaultOptionsState() // invoke the default function to reset this part of the state
    };

    default:
    return state;
  }
};
Hani
fuente
La idea de escribir el estado predeterminado como una función realmente salvó el día aquí. Gracias 🙏
Chris Paul
0

Este enfoque es muy correcto: Destruya cualquier estado específico "NOMBRE" para ignorar y conservar a los demás.

const rootReducer = (state, action) => {
    if (action.type === 'USER_LOGOUT') {
        state.NAME = undefined
    }
    return appReducer(state, action)
}
khalil zaidoun
fuente
Si solo necesita restablecer una pieza de su árbol de estado, también puede escuchar USER_LOGOUTen ese reductor y manejarlo allí.
Andy_D
0

¿Por qué no solo usas return module.exports.default();)

export default (state = {pending: false, error: null}, action = {}) => {
    switch (action.type) {
        case "RESET_POST":
            return module.exports.default();
        case "SEND_POST_PENDING":
            return {...state, pending: true, error: null};
        // ....
    }
    return state;
}

Nota: asegúrese de establecer el valor predeterminado de la acción en {}y está bien porque no desea encontrar un error cuando verifica action.typedentro de la instrucción de cambio.

Alnamrouti Fareed
fuente
0

Descubrí que la respuesta aceptada funcionó bien para mí, pero provocó el no-param-reassignerror de ESLint : https://eslint.org/docs/rules/no-param-reassign

Así 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 ...):

import { combineReducers } from "redux"
import { routerReducer } from "react-router-redux"
import ws from "reducers/ws"
import session from "reducers/session"
import app from "reducers/app"

const appReducer = combineReducers({
    "routing": routerReducer,
    ws,
    session,
    app
})

export default (state, action) => {
    const stateCopy = action.type === "LOGOUT" ? undefined : { ...state }
    return appReducer(stateCopy, action)
}

¿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:

export default (state, action) => {
    return appReducer(action.type === "LOGOUT" ? undefined : state, action)
}
skwidbreth
fuente
0

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.

rupav jain
fuente
0

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 :

 const initialState = {
    auth: {},
    theme: {},
    sidebar: {},
    lsFanpage: {},
    lsChatApp: {},
    appSelected: {},
};

export default function (state = initialState, action) {
    if (typeof isSsr!=="undefined" && isSsr) { //<== using global.isSsr = true
        state = {...initialState};//<= important "will reset the data every time there is a request from the client to the server"
    }
    switch (action.type) {
        //...other code case here
        default: {
            return state;
        }
    }
}

finalmente en el enrutador del servidor:

router.get('*', (req, res) => {
        store.dispatch({type:'reset-all-blabla'});//<= unlike any action.type // i use Math.random()
        // code ....render ssr here
});
Ngannv
fuente
0

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

  componentDidMount() {   
    this.props.persistReducerState();
  }

Reductor de la aplicación principal

const appReducer = combineReducers({
  user: userStatusReducer,     
  analysis: analysisReducer,
  incentives: incentivesReducer
});

let defaultState = null;
export default (state, action) => {
  switch (action.type) {
    case appActions.ON_APP_LOAD:
      defaultState = defaultState || state;
      break;
    case userLoginActions.USER_LOGOUT:
      state = defaultState;
      return state;
    default:
      break;
  }
  return appReducer(state, action);
};

Acción de llamada al cerrar sesión para restablecer el estado

function* logoutUser(action) {
  try {
    const response = yield call(UserLoginService.logout);
    yield put(LoginActions.logoutSuccess());
  } catch (error) {
    toast.error(error.message, {
      position: toast.POSITION.TOP_RIGHT
    });
  }
}

¡Espero que esto resuelva tu problema!

Mukundhan
fuente
0

Para restablecer el estado a su estado inicial, escribí el siguiente código:

const appReducers = (state, action) =>
   combineReducers({ reducer1, reducer2, user })(
     action.type === "LOGOUT" ? undefined : state,
     action
);
JDev
fuente
0

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:

export const selectCounter1 = (state: State) => state.counter1;
export const selectCounter2 = (state: State) => state.counter2;
export const selectTotal = createSelector(
  selectCounter1,
  selectCounter2,
  (counter1, counter2) => counter1 + counter2
);

Entonces tendrías que liberarlos al cerrar sesión de esta manera:

selectTotal.release();

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 .

Grochni
fuente
0

para mí lo que funcionó mejor es configurar el en initialStatelugar de state:

  const reducer = createReducer(initialState,
  on(proofActions.cleanAdditionalInsuredState, (state, action) => ({
    ...initialState
  })),
noy levi
fuente
-1

Otra opción es:

store.dispatch({type: '@@redux/INIT'})

'@@redux/INIT'es el tipo de acción que redux se despacha automáticamente cuando usted createStore, 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 ...

lobati
fuente
Hice que no está cambiando de estado, también probé @@ INIT, que se muestra en ReduxDevtools como primera acción
Reza
-2

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.

usuario3500325
fuente
1
¿Qué sucede si usa un middleware que sincroniza la tienda con el almacenamiento local? Entonces su enfoque no funciona en absoluto ...
Spock
8
Realmente no entiendo por qué la gente rechaza respuestas como esta.
Wylliam Judd
¿Por qué la gente ha rechazado esto? Cuando realiza un nuevo estado redux, con contenido vacío, básicamente todavía tiene los estados anteriores en la memoria, y en teoría podría acceder a los datos de ellos. ¡Actualizar el navegador ES tu apuesta más segura!
Wilhelm Sorban
-3

onLogout() {
  this.props.history.push('/login'); // send user to login page
  window.location.reload(); // refresh the page
}

Nikita Beznosikov
fuente
¿explique? @SinanSamet
Nikita Beznosikov
Para ser claros, no voté en contra de esto. Pero lo desaliento. Si navega para iniciar sesión y volver a cargar, probablemente cerrará sesión sí. Pero solo porque perdiste tu estado. A menos que use redux-persist, en cuyo caso ni siquiera cerrará sesión. En general, odio ver funciones comowindow.location.reload();
Sinan Samet el
- No escriba funciones como esta. - ¿Por qué? No me gusta.
Nikita Beznosikov
1
Recargar la página es diferente de restablecer el estado de la tienda. Además, es posible que se encuentre en un entorno sin window, por ejemplo, react-native
Max