TL; DR
Sem combineReducers()ou código manual semelhante, initialStatesempre vence state = ...no redutor porque o statepassado para o redutor é initialState e não é undefined , portanto, a sintaxe do argumento ES6 não é aplicada neste caso.
Com combineReducers()o comportamento é mais matizado. Os redutores cujo estado é especificado em initialStatereceberão isso state. Outros redutores receberão undefined e, por causa disso , voltarão ao state = ...argumento padrão que especificarem.
Em geral, initialStatevence o estado especificado pelo redutor. Isso permite que os redutores especifiquem dados iniciais que façam sentido para eles como argumentos padrão, mas também permite carregar os dados existentes (total ou parcialmente) quando você está hidratando o armazenamento a partir de algum armazenamento persistente ou do servidor.
Primeiro, vamos considerar um caso em que você tem um único redutor.
Diga que você não usa combineReducers().
Então, seu redutor pode ter a seguinte aparência:
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
Agora, digamos que você crie uma loja com ele.
import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState());
O estado inicial é zero. Por quê? Porque o segundo argumento createStoreera undefined. Este é statepassado ao seu redutor pela primeira vez. Quando o Redux é inicializado, ele despacha uma ação “fictícia” para preencher o estado. Portanto, seu counterredutor foi chamado com stateigual a undefined. Este é exatamente o caso que “ativa” o argumento padrão. Portanto, stateagora está de 0acordo com o statevalor padrão ( state = 0). Este estado ( 0) será retornado.
Vamos considerar um cenário diferente:
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState());
Por que é 42, e não 0, desta vez? Porque createStorefoi chamado com 42o segundo argumento. Este argumento passa a ser statepassado ao seu redutor junto com a ação fictícia. Desta vez, statenão é indefinido (é 42!), Então a sintaxe de argumento padrão do ES6 não tem efeito. O stateé 42e 42é retornado do redutor.
Agora vamos considerar um caso em que você usa combineReducers().
Você tem dois redutores:
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
O redutor gerado por se combineReducers({ a, b })parece com este:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
Se chamarmos createStoresem o initialState, ele inicializará o statepara {}. Portanto, state.ae state.bserá undefinedquando ele ligar ae bredutores. Ambos ae os bredutores receberão undefinedcomo seus state argumentos e, se especificarem statevalores padrão , eles serão retornados. É assim que o redutor combinado retorna um { a: 'lol', b: 'wat' }objeto de estado na primeira chamada.
import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState());
Vamos considerar um cenário diferente:
import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState());
Agora eu especifiquei o initialStatecomo o argumento para createStore(). O estado retornado do redutor combinado combina o estado inicial que eu especifiquei para o aredutor com o 'wat'argumento padrão especificado que o bpróprio redutor escolheu.
Vamos lembrar o que o redutor combinado faz:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
Neste caso, statefoi especificado para não retornar {}. Era um objeto com acampo igual a 'horse', mas sem o bcampo. É por isso que o aredutor recebeu 'horse'como seu statee alegremente o devolveu, mas o bredutor recebeu undefinedcomo seu statee, portanto, retornou sua ideia de default state(em nosso exemplo, 'wat'). É assim que recebemos { a: 'horse', b: 'wat' }em troca.
Para resumir, se você seguir as convenções do Redux e retornar o estado inicial dos redutores quando eles forem chamados com undefinedo stateargumento (a maneira mais fácil de implementar isso é especificar o statevalor do argumento padrão ES6), você terá um bom comportamento útil para redutores combinados. Eles irão preferir o valor correspondente no initialStateobjeto que você passar para a createStore()função, mas se você não passou nenhum, ou se o campo correspondente não foi definido, o padrão.state argumento especificado pelo redutor é escolhido. Esta abordagem funciona bem porque fornece inicialização e hidratação dos dados existentes, mas permite que redutores individuais redefinam seu estado se seus dados não foram preservados. Claro, você pode aplicar este padrão recursivamente, pois você pode usarcombineReducers() em muitos níveis, ou mesmo componha redutores manualmente chamando redutores e dando a eles a parte relevante da árvore de estado.
combineReducers. Muito obrigado novamente.