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. Еще раз большое спасибо.