TL; DR
Bez combineReducers()lub podobnego kodu ręcznego initialStatezawsze wygrywa state = ...w reduktorze, ponieważ stateprzekazany do reduktora jest initialState i nie jest undefined , więc składnia argumentu ES6 nie jest stosowana w tym przypadku.
Dzięki combineReducers()zachowaniu jest bardziej zniuansowany. Te reduktory, których stan jest określony w initialState, otrzymają to state. Inne reduktory otrzymają undefined iz tego powodu powrócą do state = ...domyślnego argumentu, który określą.
Generalnie initialStatewygrywa stan określony przez reduktor. Pozwala to reduktorom określić początkowe dane, które mają dla nich sens jako domyślne argumenty, ale także umożliwia ładowanie istniejących danych (w całości lub częściowo) podczas nawadniania sklepu z trwałej pamięci masowej lub serwera.
Najpierw rozważmy przypadek, w którym masz pojedynczy reduktor.
Powiedz, że nie używasz combineReducers().
Wtedy twój reduktor może wyglądać tak:
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
Teraz powiedzmy, że tworzysz z nim sklep.
import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState());
Stan początkowy wynosi zero. Czemu? Ponieważ drugim argumentem createStorebyło undefined. To jest stateprzekazane do twojego reduktora za pierwszym razem. Podczas inicjalizacji Redux wysyła „fikcyjną” akcję, aby wypełnić stan. Więc twój counterreduktor został wywołany z staterówną undefined. Dokładnie tak jest, gdy „aktywuje” domyślny argument. Dlatego statejest teraz 0zgodnie z statewartością domyślną ( state = 0). Ten stan ( 0) zostanie zwrócony.
Rozważmy inny scenariusz:
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState());
Dlaczego tym razem tak jest 42, a nie 0? Ponieważ createStorezostał wywołany 42jako drugi argument. Ten argument jest stateprzekazywany do twojego reduktora wraz z fikcyjną akcją. Tym razem statenie jest niezdefiniowana (jest 42!), Więc domyślna składnia argumentów ES6 nie ma znaczenia. stateJest 42, i 42jest zwrócony od reduktora.
Rozważmy teraz przypadek, w którym używasz combineReducers().
Masz dwa reduktory:
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
Reduktor generowany przez combineReducers({ a, b })wygląda następująco:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
Jeśli zadzwonimy createStorebez tego initialState, zainicjuje stateto {}. Dlatego state.ai state.bbędzie undefineddo czasu, gdy wzywa ai bredukuje. Oba ai breduktory otrzymają undefinedjako swoje state argumenty, a jeśli określą statewartości domyślne , zostaną one zwrócone. W ten sposób połączony reduktor zwraca { a: 'lol', b: 'wat' }obiekt stanu przy pierwszym wywołaniu.
import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState());
Rozważmy inny scenariusz:
import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState());
Teraz określiłem initialStatejako argument do createStore(). Stan zwrócony z połączonego reduktora łączy stan początkowy określony dla areduktora z 'wat'domyślnym argumentem określonym, który bsam wybrał reduktor.
Przypomnijmy, co robi kombinowany reduktor:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
W tym przypadku statezostał określony, więc nie powrócił do {}. Był to obiekt o apolu równym 'horse', ale bez bpola. Dlatego areduktor otrzymał 'horse'jako swój statei chętnie go zwrócił, ale breduktor otrzymał undefinedjako swój statei w ten sposób zwrócił swoją ideę domyślną state(w naszym przykładzie 'wat'). Tak otrzymujemy { a: 'horse', b: 'wat' }w zamian.
Podsumowując tę górę, jeśli trzymać się konwencji Redux i przywrócić stan początkowy z reduktorów, kiedy nazywa się je ze undefinedjako stateargumentu (najprostszym sposobem realizacji tego celu jest określenie statewartości domyślne argumentów ES6), będziesz mieć ładne użyteczne zachowanie dla połączonych reduktorów. Będą preferować odpowiednią wartość w initialStateobiekcie, który przekazujesz do createStore()funkcji, ale jeśli nie przekazałeś żadnej lub jeśli odpowiednie pole nie jest ustawione, statezamiast tego wybierany jest domyślny argument określony przez reduktor.To podejście działa dobrze, ponieważ zapewnia zarówno inicjalizację, jak i hydratację istniejących danych, ale umożliwia poszczególnym reduktorom resetowanie ich stanu, jeśli ich dane nie zostały zachowane. Oczywiście możesz zastosować ten wzorzec rekurencyjnie, ponieważ możesz go używać combineReducers()na wielu poziomach, a nawet ręcznie tworzyć redukcje, wywołując redukcje i dając im odpowiednią część drzewa stanu.
combineReducers. Jeszcze raz bardzo dziękuję.