Como redefinir o estado de uma loja Redux?

455

Estou usando o Redux para gerenciamento de estado.
Como redefinir a loja para seu estado inicial?

Por exemplo, digamos que eu tenho duas contas de usuário ( u1e u2).
Imagine a seguinte sequência de eventos:

  1. O usuário u1faz login no aplicativo e faz alguma coisa, por isso, armazenamos em cache alguns dados na loja.

  2. Usuário u1faz logout.

  3. O usuário u2efetua login no aplicativo sem atualizar o navegador.

Neste ponto, os dados armazenados em cache serão associados u1e eu gostaria de limpá-los.

Como posso redefinir o repositório Redux para seu estado inicial quando o primeiro usuário efetua logout?

xyz
fonte
8
É provavelmente melhor para limpar o estado ao sair em vez (a partir de uma perspectiva de segurança)
Clarkie

Respostas:

1033

Uma maneira de fazer isso seria escrever um redutor de raiz no seu aplicativo.

O redutor raiz normalmente delegaria a manipulação da ação no redutor gerado por combineReducers(). No entanto, sempre que recebe USER_LOGOUTação, ele retorna o estado inicial novamente.

Por exemplo, se o seu redutor de raiz estiver assim:

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

Você pode renomeá-lo appReducere escrever uma nova rootReducerdelegação para ele:

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

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

Agora, apenas precisamos ensinar o novo rootReducera retornar o estado inicial após a USER_LOGOUTação. Como sabemos, os redutores devem retornar o estado inicial quando são chamados undefinedcomo o primeiro argumento, independentemente da ação. Vamos usar esse fato para remover condicionalmente o acumulado à statemedida que o passamos para appReducer:

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

  return appReducer(state, action)
}

Agora, sempre que USER_LOGOUTdisparar, todos os redutores serão inicializados novamente. Eles também podem retornar algo diferente do que fizeram inicialmente, se quiserem, porque também podem verificar action.type.

Para reiterar, o novo código completo se parece com o seguinte:

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

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

  return appReducer(state, action)
}

Observe que não estou mudando o estado aqui, estou apenas reatribuindo a referência de uma variável local chamada stateantes de passá-la para outra função. Mutar um objeto de estado seria uma violação dos princípios do Redux.

Caso você esteja usando redux-persist , talvez também seja necessário limpar seu armazenamento. Redux-persist mantém uma cópia do seu estado em um mecanismo de armazenamento, e a cópia do estado será carregada a partir daí na atualização.

Primeiro, você precisa importar o mecanismo de armazenamento apropriado e, em seguida, analisar o estado antes de configurá-lo undefinede limpar cada chave de estado de armazenamento.

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
fonte
15
Estou curioso Dan, você também pode fazer algo assim no seu redutor. com CLEAR_DATA sendo a ação. case 'CLEAR_DATA': return initialState
HussienK
6
@HussienK que funcionaria, mas não no estado, para cada redutor.
Cory Danielson
12
Aqui está uma versão em que você combina dinamicamente os redutores caso utilize redutores assí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 31/08/16
2
if (action.type === 'RESET') return action.stateFromLocalStorage
Dan Abramov
3
Essa abordagem limpa completamente o estado e toda a sua história? Estou pensando da perspectiva de segurança: se isso foi implementado, uma vez que a USER_LOGOUTação foi acionada, é possível obter dados de estado mais cedo? (por exemplo, através devtools)
AlexKempton
81

Gostaria de salientar que o comentário aceito por Dan Abramov está correto, exceto que tivemos um problema estranho ao usar o pacote react-router-redux junto com essa abordagem. Nossa correção foi não definir o estado, undefinedmas ainda usar o redutor de roteamento atual. Então, eu sugiro implementar a solução abaixo se você estiver usando este pacote

const rootReducer = (state, action) => {
  if (action.type === 'USER_LOGOUT') {
    const { routing } = state
    state = { routing } 
  }
  return appReducer(state, action)
}
Ryan Irilli
fonte
19
Eu acho que o principal argumento aqui é que você pode não querer limpar toda a árvore de estado no logout - a abordagem funciona igualmente bem no redutor de raiz de qualquer subárvore e, portanto, pode ser mais claro aplicar essa técnica apenas nos redutores de raiz do subárvore (s) que você não deseja limpar, em vez de escolher 'especial' as crianças para não claro no redutor de raiz de toda a árvore, como esta
davnicwil
1
Eu acho que estou enfrentando esses problemas aos quais você está se referindo agora (onde, no logout, ele definirá a rota para o caminho certo, mas um componente completamente diferente seria carregado) eu implementei algo semelhante ao seu para corrigi-lo, mas acho que algo com js imutáveis ​​está juntando isso. I acabou criando um redutor de pai que tem ação Reset-ESTADO e eu herdar de que o redutor para evitar tocar roteamento completo
Neta Meta
Estava com problemas semelhantes, isso foi corrigido. Obrigado.
Lloyd Watkin
3
Observe que com o react-redux-router, a propriedade é routere NÃOrounting
Mrchief 15/02
2
@Mrchief depende do que você definiu como em sua combineReducers()..... se você tivesse combineReducers({routing: routingReducer})que seria como descrito na resposta
Ben Lonsdale
40

Defina uma ação:

const RESET_ACTION = {
  type: "RESET"
}

Em cada um de seus redutores, supondo que você esteja usando switchou if-elsepara lidar com várias ações através de cada redutor. Eu vou aceitar o caso por um 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; 
  }
}

Dessa forma, sempre que você chamar RESETação, seu redutor atualizará a loja com o estado padrão.

Agora, para sair, você pode lidar com o seguinte abaixo:

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

Sempre que um usuário entra, sem uma atualização do navegador. A loja estará sempre no padrão.

store.dispatch(RESET_ACTION)apenas elabora a ideia. Você provavelmente terá um criador de ações para esse fim. Uma maneira muito melhor será que você tenha um LOGOUT_ACTION.

Depois de enviar isso LOGOUT_ACTION. Um middleware personalizado pode interceptar essa ação, seja com Redux-Saga ou Redux-Thunk. Nos dois sentidos, no entanto, você pode despachar outra ação 'RESET'. Dessa forma, o logout e a redefinição da loja acontecerão de forma síncrona e sua loja estará pronta para outro login do usuário.

nirbhaygp
fonte
1
Eu sinto que esta é a melhor abordagem do que apenas definir o estado para undefinedgostar na outra resposta. quando seu aplicativo espera uma árvore de estado e você a entrega undefined, há apenas mais bugs e dores de cabeça para lidar do que apenas uma árvore vazia.
WORC
3
@worc O Estado não vai realmente ser indefinido, porque redutores retornar initialState quando recebem um estado indefinido
Guillaume
3
A @worc acha que, com essa abordagem, sempre que alguém criar um novo redutor, você precisará se lembrar de adicionar o caso de redefinição.
Francute
1
Definitivamente, mudei de idéia sobre isso, por ambos os motivos, além da ideia de que RESET_ACTION é uma ação . então, para começar, ele realmente não pertence ao redutor.
WORC
1
Esta é definitivamente a abordagem correta. Definir o estado para nada, mas o estado inicial é apenas a pedir sarilhos
Sebastian Serrano
15

Apenas uma resposta simplificada para a melhor resposta:

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


export default (state, action) =>
  rootReducer(action.type === 'USER_LOGOUT' ? undefined : state, action);
Matt Carlotta
fonte
isso está funcionando obrigado, eu fui da resposta de Dan, mas não consigo descobrir.
Aljohn Yamaro
14
 const reducer = (state = initialState, { type, payload }) => {

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

   return state
 }

Você também pode disparar uma ação que é manipulada por todos ou alguns redutores que deseja redefinir para o armazenamento inicial. Uma ação pode desencadear uma redefinição para todo o seu estado, ou apenas um pedaço que lhe pareça adequado. Eu acredito que esta é a maneira mais simples e controlável de fazer isso.

Daniel petrov
fonte
10

Com o Redux, se você aplicou a solução a seguir, que assume que eu configurei um initialState em todos os meus redutores (por exemplo, {usuário: {nome, email}}). Em muitos componentes, verifico essas propriedades aninhadas, portanto, com essa correção, evito que meus métodos de renderização sejam quebrados em condições de propriedade acopladas (por exemplo, se state.user.email, que gerará um erro, o usuário não será definido se as soluções mencionadas acima).

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
fonte
7

ATUALIZAÇÃO NGRX4

Se você estiver migrando para o NGRX 4, pode ter notado no guia de migração que o método redutor de raiz para combinar seus redutores foi substituído pelo método ActionReducerMap. A princípio, essa nova maneira de fazer as coisas pode tornar um estado de redefinição um desafio. Na verdade, é direto, mas a maneira de fazer isso mudou.

Esta solução é inspirada na seção API de meta-redutores dos documentos do NGRX4 Github.

Primeiro, digamos que você esteja combinando seus redutores dessa maneira usando a nova opção ActionReducerMap da 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
}

Agora, digamos que você deseja redefinir o estado no 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 { }

`

E essa é basicamente uma maneira de obter o mesmo efeito com o NGRX 4.

Tyler Brown
fonte
5

Combinando as abordagens de Dan, Ryan e Rob, para manter o routerestado e inicializar tudo na árvore do estado, acabei com isso:

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

Eu criei um componente para dar ao Redux a capacidade de redefinir o estado; você só precisa usar esse componente para aprimorar sua loja e enviar um action.type específico para acionar a redefinição. O pensamento de implementação é o mesmo que @Dan Abramov disse.

Github: https://github.com/wwayne/redux-reset

Wwayne
fonte
4

Eu criei ações para limpar o estado. Portanto, quando despacho um criador de ações de logoff, despacho ações para limpar o estado também.

Ação de registro do usuário

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

Criador de ações de logout

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

Redutor

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
  }
};

Não tenho certeza se isso é ideal?

Navinesh Chand
fonte
2

Se você estiver usando ações redux , aqui está uma solução rápida usando um HOF ( Função de ordem superior ) para handleActions.

import { handleActions } from 'redux-actions';

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

E, em seguida, use em handleActionsExvez do original handleActionspara lidar com redutores.

A resposta de Dan dá uma ótima idéia sobre esse problema, mas não funcionou bem para mim, porque estou usando redux-persist.
Quando usado com redux-persist, simplesmente passar o undefinedestado não aciona o comportamento persistente, então eu sabia que tinha que remover manualmente o item do armazenamento (React Native no meu caso, portanto AsyncStorage).

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

ou

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

também não funcionou para mim - eles apenas gritaram comigo. (por exemplo, reclamando como "chave inesperada _persist ..." )

De repente, ponderei tudo que desejo é apenas fazer com que cada redutor individual retorne seu próprio estado inicial quando RESETum tipo de ação é encontrado. Dessa forma, persistir é tratado naturalmente. Obviamente, sem a função utilidade acima ( handleActionsEx), meu código não parecerá SECO (embora seja apenas um liner, por exemplo RESET: () => initialState), mas eu não aguentava, porque eu amo metaprogramação.

elquimista
fonte
2

A seguinte solução funcionou para mim.

Adicionei a redefinição da função de estado aos meta redutores. A chave era usar

return reducer(undefined, action);

para definir todos os redutores para o estado inicial. O retorno undefinedestava causando erros devido ao fato de a estrutura da loja ter sido destruída.

/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
fonte
2

A partir de uma perspectiva de segurança, a coisa mais segura a fazer quando registrar uma saída de usuário é para repor todo o estado persistente (ex cookies, localStorage, IndexedDB, Web SQL, etc) e fazer uma atualização forçada da página usando window.location.reload(). É possível que um desenvolvedor desleixado, acidental ou intencionalmente, armazene alguns dados confidenciais windowno DOM, etc. Afastar todo o estado persistente e atualizar o navegador é a única maneira de garantir que nenhuma informação do usuário anterior vaze para o próximo usuário.

(É claro que, como usuário em um computador compartilhado, você deve usar o modo "navegação privada", fechar a janela do navegador, usar a função "limpar dados de navegação", etc., mas como desenvolvedor, não podemos esperar que todos estejam sempre diligente)

tlrobinson
fonte
1
Por que as pessoas votaram contra isso? Quando você cria um novo estado redux, com conteúdo vazio, basicamente ainda possui os estados anteriores na memória e, teoricamente, pode acessar os dados a partir deles. Atualizar o navegador É a sua aposta mais segura!
Wilhelm Sorban
2

Minha solução alternativa ao trabalhar com texto datilografado, construído com base na resposta de Dan (as reduções do redux tornam impossível passar undefinedpara o redutor como primeiro argumento, por isso, eu coloco em cache o estado raiz inicial em uma 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
fonte
2

A resposta aceita me ajudou a resolver meu caso. No entanto, encontrei um caso em que não era preciso limpar todo o estado. Então - eu fiz assim:

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 isso ajude alguém :)

pesho hristov
fonte
e se eu tiver mais de 10 estados, mas desejar redefinir o estado de apenas um redutor?
Paulo
1

Apenas uma extensão para a resposta @ dan-abramov , às vezes podemos precisar reter certas teclas da redefinição.

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
fonte
1

Uma opção rápida e fácil que funcionou para mim foi usar redux-reset . O que foi direto e também possui algumas opções avançadas para aplicativos maiores.

Configuração na loja de criação

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)

Despache seu 'reset' na sua função de logout

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

Espero que isto ajude

Munei Nengwenani
fonte
1

Minha opinião para impedir o Redux de fazer referência à mesma variável do 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
fonte
A ideia de escrever o estado padrão como uma função realmente salvou o dia aqui. Obrigado 🙏
Chris Paul
0

Essa abordagem é muito correta: destrua qualquer estado específico "NAME" para ignorar e manter outros.

const rootReducer = (state, action) => {
    if (action.type === 'USER_LOGOUT') {
        state.NAME = undefined
    }
    return appReducer(state, action)
}
khalil zaidoun
fonte
Se você precisar redefinir apenas uma parte da sua árvore de estados, também poderá ouvir USER_LOGOUTnesse redutor e manipulá-lo lá.
21416 Andy_D
0

por que você não usa 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: certifique-se de definir o valor padrão da ação {}e se você está bem, pois não deseja encontrar erros ao verificar action.typedentro da instrução switch.

Alnamrouti com tarifa
fonte
0

Descobri que a resposta aceita funcionou bem para mim, mas acionou o no-param-reassignerro ESLint - https://eslint.org/docs/rules/no-param-reassign

Aqui está como eu lidei com isso, certificando-se de criar uma cópia do estado (que é, no meu entender, a coisa Reduxy a ser feita ...):

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

Mas talvez criar uma cópia do estado para passá-lo para outra função redutora que crie uma cópia um pouco complicada demais? Isso não parece tão bem, mas é mais direto ao ponto:

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

Além da resposta de Dan Abramov, não devemos definir explicitamente ação como action = {type: '@@ INIT'} ao lado de state = undefined. Com o tipo de ação acima, todo redutor retorna o estado inicial.

rupav jain
fonte
0

no servidor, tenho uma variável é: global.isSsr = true e, em cada redutor, tenho uma const é: initialState Para redefinir os dados na loja, faça o seguinte com cada redutor: exemplo com 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 no roteador do servidor:

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

A seguinte solução funciona para mim.

Primeiro, no início de nossa aplicação, o estado do redutor é novo e novo com o InitialState padrão .

Temos que adicionar uma ação que solicite a carga inicial do APP para persistir no estado padrão .

Ao sair do aplicativo, podemos simplesmente reatribuir o estado padrão e o redutor funcionará como novo .

Contêiner APP principal

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

Redutor principal de APP

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);
};

Na ação de chamada de Logoff para redefinir o 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 isso resolva seu problema!

Mukundhan
fonte
0

Para eu redefinir o estado para seu estado inicial, escrevi o seguinte código:

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

Uma coisa que a solução na resposta aceita não faz é limpar o cache dos seletores parametrizados. Se você tiver um seletor 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
);

Então você teria que liberá-los no logout como este:

selectTotal.release();

Caso contrário, o valor memorizado para a última chamada do seletor e os valores dos últimos parâmetros ainda estarão na memória.

As amostras de código são dos documentos do ngrx .

Grochni
fonte
0

para mim, o que funcionou melhor é definir o em initialStatevez de state:

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

Outra opção é:

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

'@@redux/INIT'é o tipo de ação que o redux despacha automaticamente quando você createStore, portanto, supondo que todos os seus redutores já tenham um padrão, isso seria detectado por eles e iniciaria seu estado de novo. Porém, pode ser considerado um detalhe de implementação privada do redux, portanto, o comprador deve ficar atento ...

lobati
fonte
Eu fiz que não está mudando de estado, também eu tentei @@ INIT que é mostrado no ReduxDevtools como primeira ação
Reza
-2

Simplesmente faça com que seu link de logout limpe a sessão e atualize a página. Nenhum código adicional é necessário para sua loja. Sempre que você desejar redefinir completamente o estado, uma atualização de página é uma maneira simples e fácil de repetir para lidar com isso.

user3500325
fonte
1
E se você usar um middleware que sincronize a loja com o armazenamento local? Em seguida, a sua abordagem não funciona em tudo ...
Spock
8
Eu realmente não entendo por que as pessoas votam negativamente respostas como esta.
Wylliam Judd 07/02
Por que as pessoas votaram contra isso? Quando você cria um novo estado redux, com conteúdo vazio, basicamente ainda possui os estados anteriores na memória e, teoricamente, pode acessar os dados a partir deles. Atualizar o navegador É a sua aposta mais segura!
Wilhelm Sorban
-3

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

Nikita Beznosikov
fonte
explicar? @SinanSamet
Nikita Beznosikov 19/11/19
Para deixar claro, não votei contra isso. Mas eu desencorajo isso. Se você navegar para fazer login e recarregar, provavelmente sairá sim. Mas apenas porque você perdeu seu estado. A menos que você use redux-persist, nesse caso, você nem fará logout. No geral, eu odeio ver funções comowindow.location.reload();
Sinan Samet
- Não escreva funções como esta. - Por quê? Eu não gosto disso.
Nikita Beznosikov 22/11/19
1
Recarregar a página é diferente de redefinir o estado da loja. Além disso, você pode estar em um ambiente sem window, por exemplo, reagir nativo
Max