对createStore在Redux中的工作方式感到困惑

时间:2020-05-02 05:40:33

标签: redux

我正在学习Redux,并遇到了createStore函数。因此,据我所知,createStore接收3个参数:

reducer
initial state
enhancers (for simplicity we will use only middlewares)

但是当我们在操作中使用createStore时,我们不会将初始状态作为第二个参数传递,而是通过带有默认状态的reducer传递,如下所示:

const initialState = {counter:0}
const reducer =(state=initialState, action)=>...

问题是为什么我们不将初始状态作为第二个参数,而是将initialState传递给reducer?

3 个答案:

答案 0 :(得分:1)

我认为您正在将 reduceer initial状态与应用的全局状态相混淆。

全局状态仅表示应用程序中所有reducer的组合状态。

为简单起见,我们假设您的应用程序中只有一个减速器。

减速器:

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([action.text])
    default:
      return state
  }
}

因此,这个简单的功能todos是我们的约简工具,它将在运行时为我们提供当前状态树。

这是我们createStore的第一个参数。

初始状态:

['Understanding Store']

让我们假设我们的初始状态是一个包含1个项的数组,如上所述。

这是我们createStore的第二个参数。

现在,我们像这样创建商店:

import { createStore } from 'redux'

//... code
.
.
.
const store = createStore(todos, ['Understanding Store'])

现在我们的商店已创建。 没什么,存储基本上是一个对象,上面没有什么方法。

其中一种方法是dispatch。 此方法有助于dispatching执行操作,该操作将通过我们的reducer运行,然后更新状态。

所以当我们这样做

store.dispatch({
  type: 'ADD_TODO',
  text: 'Learn methods on Store'
})

这将更新我们的状态,如下所示:

['Understanding Store','Learn methods on Store']

但是,当您的应用程序变大时,您可能想要创建不同的功能(缩减器)来管理全局状态的不同部分。

如果我们还有另一个减速器,请说counter.js

export default function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }

}

然后结合我们的第一个reducer待办事项和此计数器reducer,我们有了一个名为combineReducer的实用程序。

rootReducer.js

import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'

export default combineReducers({
  todos,
  counter
})

然后使用createStore,您只需执行以下操作:

import { createStore } from 'redux'
import rootReducer from './rootReducer.js;

const store = createStore(rootReducer);

使用combineReducers时需要遵循某些规则。

阅读规则here

答案 1 :(得分:0)

createStore中传递初始状态作为第二个参数的用例适用于在加载应用程序时从外部获得此初始状态的用例。例如,可能是在服务器上为客户端上水合的服务器端渲染应用程序生成的状态,或者是在加载时从本地存储还原redux状态的应用程序。

在使用未定义状态调用reducer函数时,应返回单个reducer的初始值,最简单的方法是对state使用默认参数:

const reducer = (state = initialState, action) => ...

这使您可以在简化器定义的位置附近定义initialState,并且在具有大量简化器的情况下,它可以与combineReducers很好地缩放。如果将所有化简器的所有initialState放入一个传递给createStore的对象中,将很难保持同步。

答案 2 :(得分:0)

我认为您实际上已经将createStore与reducer混淆了。将createStore视为一个函数,该函数通过添加某些MiddleWares和其他功能(如dispatch

)来返回简化器的集合

在您的应用中,您经常会使用多个reducer,实际上您使用combineReducers

来组合它们

例如,您的CombineReducers是

import userReducer from 'reducers/user';
import authReducer from 'reducers/auth';
import countReducer from 'reducers/count';
const reducers = combineReducers({
   userReducer,
   authReducer,
   countReducer,
});

现在,createStore的initialState必须为对象格式,其键为userReducer, authReducer, countReducer,然后是单个化简器状态。例如

{
   userReducer: { id: 1, name: 'Test'},
   authReducer: { isLoading: true, isAuthenticated: false},
   countReducer: {counter: 0}
}

第二个键现在相当于每个单独的reducer

例如:reducer / count.js

const initialState = {counter:0}
const reducer =(state=initialState, action)=>...

它的工作方式是,每次调用动作时,createStore实际上都会使用该动作调用reducer

reducer(state, action);

对于CombineReducer,其工作方式如下

const combineReducers = (reducers) => {
    return (state, action) => {
        const tempState = { ...state };
        Object.keys(reducers).forEach((key) => {
            tempState[key] = reducers[key](tempState[key], action);
        });
        return tempState;
    };
};

,并在最初使用它调用

reducer(initialState, {type: "@@redux/INIT"});

以便填充每个异径管的初始状态

P.S.如果您没有将initialState传递给createStore,则每个化简器都像const reducer =(state=initialState, action)=>一样接受传递给它的默认参数,并返回默认switch子句的状态,从而导致每个化简器中的initialState为用过