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 ( u1
e u2
).
Imagine a seguinte sequência de eventos:
O usuário
u1
faz login no aplicativo e faz alguma coisa, por isso, armazenamos em cache alguns dados na loja.Usuário
u1
faz logout.O usuário
u2
efetua login no aplicativo sem atualizar o navegador.
Neste ponto, os dados armazenados em cache serão associados u1
e eu gostaria de limpá-los.
Como posso redefinir o repositório Redux para seu estado inicial quando o primeiro usuário efetua logout?
Respostas:
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 recebeUSER_LOGOUT
ação, ele retorna o estado inicial novamente.Por exemplo, se o seu redutor de raiz estiver assim:
Você pode renomeá-lo
appReducer
e escrever uma novarootReducer
delegação para ele:Agora, apenas precisamos ensinar o novo
rootReducer
a retornar o estado inicial após aUSER_LOGOUT
ação. Como sabemos, os redutores devem retornar o estado inicial quando são chamadosundefined
como o primeiro argumento, independentemente da ação. Vamos usar esse fato para remover condicionalmente o acumulado àstate
medida que o passamos paraappReducer
:Agora, sempre que
USER_LOGOUT
disparar, todos os redutores serão inicializados novamente. Eles também podem retornar algo diferente do que fizeram inicialmente, se quiserem, porque também podem verificaraction.type
.Para reiterar, o novo código completo se parece com o seguinte:
Observe que não estou mudando o estado aqui, estou apenas reatribuindo a referência de uma variável local chamada
state
antes 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
undefined
e limpar cada chave de estado de armazenamento.fonte
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
ação foi acionada, é possível obter dados de estado mais cedo? (por exemplo, através devtools)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,
undefined
mas ainda usar o redutor de roteamento atual. Então, eu sugiro implementar a solução abaixo se você estiver usando este pacotefonte
router
e NÃOrounting
combineReducers()
..... se você tivessecombineReducers({routing: routingReducer})
que seria como descrito na respostaDefina uma ação:
Em cada um de seus redutores, supondo que você esteja usando
switch
ouif-else
para lidar com várias ações através de cada redutor. Eu vou aceitar o caso por umswitch
.Dessa forma, sempre que você chamar
RESET
ação, seu redutor atualizará a loja com o estado padrão.Agora, para sair, você pode lidar com o seguinte abaixo:
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 umLOGOUT_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.fonte
undefined
gostar na outra resposta. quando seu aplicativo espera uma árvore de estado e você a entregaundefined
, há apenas mais bugs e dores de cabeça para lidar do que apenas uma árvore vazia.Apenas uma resposta simplificada para a melhor resposta:
fonte
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.
fonte
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).
fonte
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:
Agora, digamos que você deseja redefinir o estado no app.module `
`
E essa é basicamente uma maneira de obter o mesmo efeito com o NGRX 4.
fonte
Combinando as abordagens de Dan, Ryan e Rob, para manter o
router
estado e inicializar tudo na árvore do estado, acabei com isso:fonte
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
fonte
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
Criador de ações de logout
Redutor
Não tenho certeza se isso é ideal?
fonte
Se você estiver usando ações redux , aqui está uma solução rápida usando um HOF ( Função de ordem superior ) para
handleActions
.E, em seguida, use em
handleActionsEx
vez do originalhandleActions
para 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 oundefined
estado não aciona o comportamento persistente, então eu sabia que tinha que remover manualmente o item do armazenamento (React Native no meu caso, portantoAsyncStorage
).ou
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
RESET
um 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 exemploRESET: () => initialState
), mas eu não aguentava, porque eu amo metaprogramação.fonte
A seguinte solução funcionou para mim.
Adicionei a redefinição da função de estado aos meta redutores. A chave era usar
para definir todos os redutores para o estado inicial. O retorno
undefined
estava causando erros devido ao fato de a estrutura da loja ter sido destruída./reducers/index.ts
app.module.ts
fonte
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 usandowindow.location.reload()
. É possível que um desenvolvedor desleixado, acidental ou intencionalmente, armazene alguns dados confidenciaiswindow
no 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)
fonte
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
undefined
para o redutor como primeiro argumento, por isso, eu coloco em cache o estado raiz inicial em uma constante):fonte
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:
Espero que isso ajude alguém :)
fonte
Apenas uma extensão para a resposta @ dan-abramov , às vezes podemos precisar reter certas teclas da redefinição.
fonte
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
Despache seu 'reset' na sua função de logout
Espero que isto ajude
fonte
Minha opinião para impedir o Redux de fazer referência à mesma variável do estado inicial:
fonte
Essa abordagem é muito correta: destrua qualquer estado específico "NAME" para ignorar e manter outros.
fonte
USER_LOGOUT
nesse redutor e manipulá-lo lá.por que você não usa
return module.exports.default()
;)Nota: certifique-se de definir o valor padrão da ação
{}
e se você está bem, pois não deseja encontrar erros ao verificaraction.type
dentro da instrução switch.fonte
Descobri que a resposta aceita funcionou bem para mim, mas acionou o
no-param-reassign
erro ESLint - https://eslint.org/docs/rules/no-param-reassignAqui 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 ...):
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:
fonte
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.
fonte
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 :
finalmente no roteador do servidor:
fonte
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
Redutor principal de APP
Na ação de chamada de Logoff para redefinir o estado
Espero que isso resolva seu problema!
fonte
Para eu redefinir o estado para seu estado inicial, escrevi o seguinte código:
fonte
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:
Então você teria que liberá-los no logout como este:
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 .
fonte
para mim, o que funcionou melhor é definir o em
initialState
vez destate
:fonte
Outra opção é:
'@@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 ...fonte
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.
fonte
fonte
window.location.reload();
window
, por exemplo, reagir nativo