在Redux Reducer中读取Store的初始状态

时间:2015-11-17 05:24:47

标签: javascript reactjs redux

Redux应用程序中的初始状态可以通过两种方式设置:

  • 将其作为第二个参数传递给tic mitdata; % load data data=dmso; % take the 'DMSO' column data num=length(data); mm=linspace(.1, 1, 2)'; % mean values vv=linspace(.1, 2, 2)'; % variance values N=length(mm); n=length(vv); % get all combinations of the initial parameter guesses I want to try pp = cell(N, n); for i = 1:N for j = 1:n pp{(i-1)*N+j} = [mm(i), vv(j)]; end end temp = nchoosek([1:N*n, 1:N*n], 2); temp = sort(temp, 2); idx = unique(temp, 'rows'); P = zeros(length(idx),4); for ii = 1:length(idx) P(ii,:) = [pp{idx(ii,1)},pp{idx(ii,2)}]; end Pcell = num2cell(P); % convert P to cell so that it's easier to assign parameter values for initial guess options = statset('MaxIter',10000, 'MaxFunEvals',10000); pd = zeros(length(P),4); % space for best fit parameters ld = NaN*ones(length(P),1); % space for likelihood values parfor i=1:length(P) [m1,v1,m2,v2] = Pcell{i,:}; x0 = [m1,v1,m2,v2]; % initial guess [p,conf1]=mle(data,'pdf',@convolv_2invG,'start',x0, 'upperbound', [Inf Inf Inf Inf],'lowerbound',[0 0 0 0],'options',options) pd(i,:)=p; % get best fit parameters from MLE l=convolv_2invG(data,p(1),p(2),p(3),p(4)); % use best fit parameters to evaluate pdf l=sum(log(l)); if l<0 ld(i)=l; % store likelihood values end end toc docs link
  • 将其作为第一个参数传递给(子)缩减器(docs link

如果您将初始状态传递到商店,那么如何从商店中读取该状态并将其作为减速器中的第一个参数?

4 个答案:

答案 0 :(得分:170)

  

TL; DR

     

如果没有combineReducers()或类似的手动代码,initialState总是胜过减速器中的state = ...,因为传递给reducer state { {1}}和不是 initialState,因此在这种情况下不会应用ES6参数语法。

     

使用undefined行为会更加微妙。那些在combineReducers()中指定状态的缩减器将收到initialState。其他Reducer将收到state ,因此将回退到他们指定的undefined默认参数。

     

通常,state = ...胜过reducer指定的状态。这使得Reducer可以将对它们有意义的初始数据指定为默认参数,但是当您从某个持久存储或服务器中保存商店时,还允许加载现有数据(完全或部分)。

首先让我们考虑一下你有一个减速机的情况 假设您没有使用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。这是第一次传递给你的reducer的undefined。当Redux初始化时,它会调度“虚拟”动作来填充状态。因此,state缩减器的调用时counter等于state这就是“激活”默认参数的情况。因此,根据默认undefinedstate0现在为state )。将返回此状态(state = 0)。

让我们考虑一个不同的场景:

0

为什么这次是import { createStore } from 'redux'; let store = createStore(counter, 42); console.log(store.getState()); // 42 而不是42?因为0被调用createStore作为第二个参数。此参数变为与{0}传递给减速器的42以及虚拟动作。 这一次,state未定义(它是state!),因此ES6默认参数语法无效。 42为{{ 1}},并且从reducer返回state

现在让我们考虑使用42的情况 你有两个减速器:

42

combineReducers()生成的reducer如下所示:

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.astate.b缩减器时将为undefined ab缩减器都会收到a 他们的 b参数,如果他们指定默认undefined值,这些将被返回。这是组合的reducer在第一次调用时返回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' } 的参数。从合并的reducer 返回的状态组合我为initialState reducer指定的初始状态与createStore() reducer选择自己的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的方式。

总结一下,如果你坚持使用Redux约定并在使用'wat'作为{ a: 'horse', b: 'wat' }参数调用时从reducers返回初始状态(最简单的实现方法是要指定undefined ES6默认参数值),您将对组合缩减器有一个很好的有用行为。 他们会更喜欢您传递给state函数的state对象中的相应值,但如果您没有传递任何值,或者未设置相应的字段,则默认改为使用reducer指定的initialState参数。这种方法效果很好,因为它提供了现有数据的初始化和水合,但是如果没有保留数据,则允许各个reducers重置其状态。当然,您可以递归地应用此模式,因为您可以在许多级别上使用createStore(),甚至可以通过调用reducers并为它们提供状态树的相关部分来手动编写Reducer。

答案 1 :(得分:5)

简而言之:Redux是一个将初始状态传递给Reducer的人,你不需要做任何事情。

当你致电createStore(reducer, [initialState])时,你会让Redux知道在第一个动作进入时传递给reducer的初始状态是什么。

您提到的第二个选项仅适用于您在创建商店时未通过初始状态的情况。即。

function todoApp(state = initialState, action)

只有在Redux没有通过状态的情况下才会初始化状态

答案 2 :(得分:1)

  

如何从商店中读取该状态并将其作为减速器中的第一个参数?

combineReducers()为你完成这项工作。 写它的第一种方式并不是真的有用:

const rootReducer = combineReducers({ todos, users })

但另一个,相当于更清楚:

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

答案 3 :(得分:0)

我希望这能回答你的请求(我理解为在传递intialState并返回该状态时初始化reducers)

我们这样做(警告:从Typescript代码复制)。

它的要点是mainReducer(工厂)函数中的if(!state)测试

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 ) {
            ....
        }
    }
}