Вопрос по redux, javascript, reactjs – Читать начальное состояние магазина в Redux Reducer

79

Начальное состояние в приложении Redux можно установить двумя способами:

передать его в качестве второго аргументаcreateStore (ссылка на документы)передать его в качестве первого аргумента вашим (под) редукторам (ссылка на документы)

Если вы передаете начальное состояние в свой магазин, как вы читаете это состояние из магазина и делаете его первым аргументом в ваших редукторах?

Ваш Ответ

4   ответа
0

что это отвечает на ваш запрос (который я понял как инициализация редукторов при передаче intialState и возвращении этого состояния)

Вот как мы это делаем (предупреждение: скопировано из кода Typescript).

Суть этого являетсяif(!state) тест в функции mainReducer (заводской)

function getInitialState(): MainState {

     return {
         prop1:                 'value1',
         prop1:                 'value2',
         ...        
     }
}



const reducer = combineReducers(
    {
        main:     mainReducer( getInitialState() ),
        ...
    }
)



const mainReducer = ( initialState: MainState ): Reducer => {

    return ( state: MainState, action: Action ): MainState => {

        if ( !state ) {
            return initialState
        }

        console.log( 'Main reducer action: ', action ) 

        switch ( action.type ) {
            ....
        }
    }
}
1

ом в ваших редукторах?

зерноуборочный комбайн () сделает всю работу за вас. Первый способ написать это не очень полезно:

const rootReducer = combineReducers({ todos, users })

Но другой, эквивалентный, более понятен:

function rootReducer(state, action) {
   todos: todos(state.todos, action),
   users: users(state.users, action)
}
5

именно Redux передает исходное состояние редукторам, вам не нужно ничего делать.

Когда вы звонитеcreateStore(reducer, [initialState]) вы даете Redux знать, какое начальное состояние должно быть передано редуктору при появлении первого действия.

Второй вариант, который вы упомянули, применяется только в том случае, если вы не прошли начальное состояние при создании магазина. то есть

function todoApp(state = initialState, action)

состояние будет инициализировано, только если Redux не передал состояние

Спасибо, но мой вопрос должен быть неясным. Я буду ждать, чтобы увидеть, если другие ответят перед редактированием. cantera
Спасибо за ответ - в случае композиции редуктора, если вы применили начальное состояние к хранилищу, как вы сообщите дочернему / подчиненному редуктору, какой части исходного дерева состояний оно принадлежит? Например, если у вас естьmenuStateКак мне сказать редуктор меню, чтобы прочитать значениеstate.menu из магазина и использовать его в качестве исходного состояния? cantera
166
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()); // 0

Начальное состояние - ноль. Зачем? Потому что второй аргумент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

Почему это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 }) выглядит так:

// const combined = 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()); // { a: 'lol', b: 'wat' }

Давайте рассмотрим другой сценарий:

import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState()); // { a: 'horse', b: 'wat' }

Теперь я указалinitialState в качестве аргументаcreateStore(), Состояние возвращено с комбинированного редукторакомбинаты начальное состояние, которое я указал дляa редуктор с'wat' заданный по умолчанию аргументb Редуктор выбрал сам.

Давайте вспомним, что делает комбинированный редуктор:

// const combined = combineReducers({ a, 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() на многих уровнях или даже составлять редукторы вручную, вызывая редукторы и предоставляя им соответствующую часть дерева состояний.

@ConAntonakos Нет, я не это имел в виду. Я имею в виду выбор исходного состояния именно там, где вы определяете редуктор, например,function counter(state = 0, action) или жеfunction visibleIds(state = [], action). Dan Abramov
@jasan: используйте localStorage.egghead.io/lessons/... Dan Abramov
Спасибо за этот ответ, Дэн. Если я правильно перевариваю ваш ответ, вы говорите, что было бы лучше установить начальное состояние через тип действия редуктора? Например, GET_INITIAL_STATE и вызвать диспетчеризацию для этого типа действия в, скажем, обратном вызове componentDidMount? Con Antonakos
Это просто блестящая рецензия для начинающих. По сути, я искал для загрузки начальную группу данных для моего приложения, и теперь я знаю, что лучший способ сделать это - создать данные в семенном редукторе. pihyper

Похожие вопросы