TL; DR
Без combineReducers()або подібного ручного коду initialStateзавжди перемагає state = ...в редукторі, тому що stateпереданий редуктору є initialState і ні undefined , тому синтаксис аргументу ES6 у цьому випадку не застосовується.
З combineReducers()поведінкою більш тонко. Ті редуктори, стан яких вказаний у initialState, отримають це state. Інші редуктори отримають undefined і через це повернуться до state = ...аргументу за замовчуванням, який вони вказали.
Загалом, initialStateвиграє держава, визначена редуктором. Це дозволяє редукторам вказувати початкові дані, які мають сенс для них, як аргументи за замовчуванням, але також дозволяє завантажувати наявні дані (повністю або частково), коли ви зволожуєте магазин із постійного сховища або сервера.
Спочатку розглянемо випадок, коли у вас є один редуктор.
Скажімо, ви не використовуєте combineReducers().
Тоді ваш редуктор може виглядати так:
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
Тепер, припустимо, ви створюєте з ним магазин.
import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState());
Початковий стан дорівнює нулю. Чому? Тому що другим аргументом createStoreбуло undefined. Це stateпередано вашому редуктору вперше. Коли Redux ініціалізується, він відправляє "фіктивну" дію для заповнення стану. Отже, ваш counterредуктор викликали з stateрівним undefined. Це саме той випадок, який «активує» аргумент за замовчуванням. Отже, stateзараз 0відповідає stateзначенням за замовчуванням ( state = 0). Цей стан ( 0) буде повернено.
Давайте розглянемо інший сценарій:
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState());
Чому це 42, а ні 0, цього разу? Тому що createStoreбув викликаний 42як другий аргумент. Цей аргумент стає stateпереданим вашому редуктору разом із фіктивною дією. Цього разу stateне визначено (це 42!), Тому синтаксис аргументу ES6 за замовчуванням не впливає. stateЦе 42, і 42повертається з редуктора.
Тепер давайте розглянемо випадок, коли ви використовуєте combineReducers().
У вас є два редуктори:
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
Знижений редуктор combineReducers({ a, b })виглядає так:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
Якщо ми називаємо createStoreбез initialState, це буде форматувати stateв {}. Тому state.aі state.bбуде undefinedдо того моменту, коли він зателефонує aі bредукторам. І аргументи, aі bредуктори отримають undefinedяк свої state аргументи, і якщо вони вкажуть stateзначення за замовчуванням , вони будуть повернуті. Ось як комбінований редуктор повертає об’єкт { a: 'lol', b: 'wat' }стану при першому виклику.
import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState());
Давайте розглянемо інший сценарій:
import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState());
Тепер я вказав initialStateаргумент як аргумент createStore(). Стан, повернутий із комбінованого редуктора, поєднує початковий стан, який я вказав для aредуктора, із 'wat'аргументом за замовчуванням, вказаним тим, що bредуктор вибрав сам.
Давайте згадаємо, що робить комбінований редуктор:
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
У цьому випадку stateбуло вказано, щоб не повертатися до {}. Це був об’єкт із aполем, рівним 'horse', але без bполя. Ось чому aредуктор отримав 'horse'як свій stateі із задоволенням повернув його, але bредуктор отримав undefinedяк свій stateі таким чином повернув свою ідею за замовчуванням state(у нашому прикладі, 'wat'). Отак ми отримуємо { a: 'horse', b: 'wat' }взамін.
Підводячи підсумок, якщо ви дотримуєтеся конвенцій Redux і повертаєте початковий стан від редукторів, коли вони викликаються undefinedяк stateаргумент (найпростіший спосіб реалізувати це вказати stateзначення аргументу за замовчуванням ES6), приємна корисна поведінка для комбінованих редукторів. Вони віддадуть перевагу відповідному значенню в initialStateоб'єкті, який ви createStore()передаєте функції, але якщо ви не передали жодного або якщо відповідне поле не встановлено, stateзамість цього вибирається аргумент за замовчуванням, вказаний редуктором.Цей підхід працює добре, оскільки забезпечує як ініціалізацію, так і гідратацію існуючих даних, але дозволяє окремим редукторам скинути свій стан, якщо їх дані не збереглися. Звичайно, ви можете застосовувати цей шаблон рекурсивно, оскільки ви можете використовувати його combineReducers()на багатьох рівнях, або навіть складати редуктори вручну, викликаючи редуктори та надаючи їм відповідну частину дерева стану.
combineReducers. Дякую ще раз.