redux(二)- 实现

实现简易版的 createStore 及 combineReducers。

createStore#

createStore:创建一个 Redux store 来以存放应用中所有的 state。应用中应有且仅有一个 store。

参数#

reducer#

  • Type: Function
  • Required

接收两个参数,分别是当前的 state 树和要处理的 action,并返回新的 state 树

function reducer(state = {}, action) {
switch (action.type) {
case 'increase':
return { ...state, num: state.num + (action.num || 1) };
case 'decrease':
return { ...state, num: state.num - (action.num || 1) };
default:
return state;
}
}

preloadedState#

  • Type: any

State 的初始值,

enhancer#

  • Type: Function

用于组合 store creator 的高阶函数,返回一个新的强化过的 store creator。这与 middleware 相似,它也允许你通过复合函数改变 store 接口。

返回值#

Store#

  • Store.getState 获取状态树 state
  • Store.dispatch 修改状态树的唯一方式
  • Store.subscribe 订阅,接收一个函数,并返回解约函数,当状态改变时触发
function createStore(reducer, preloadedState, enhancer) {
function getState() {}
function subscribe() {}
function dispatch() {}
return {
dispatch,
subscribe,
getState,
};
}

实现#

根据 Redux 核心概念及函数定义,实现 createStore 简易版如下:

function createStore(reducer, preloadedState, enhancer) {
if (enhancer) {
return enhancer(createStore)(reducer, preloadedState);
}
let currentReducer = reducer;
let currentState = preloadedState; // 记录所有状态的 state
let currentListeners = []; // 通过 subscribe 注册的一系列监听回调
function getState() {
return currentState;
}
function dispatch(action) {
// 通过 reducer 修改当前的状态 state
currentState = currentReducer(currentState, action);
// 发布
for (let i = 0; i < currentListeners.length; i++) {
const listener = currentListeners[i];
listener();
}
return action; // 注意:此处为什么返回 action?
}
// 注册监听回到,保存至 currentListeners,并返回相应的注销函数
function subscribe(listener) {
currentListeners.push(listener);
return function unsubscribe() {
const index = currentListeners.indexOf(listener);
currentListeners.splice(index, 1);
};
}
// 返回 Store
return {
dispatch,
subscribe,
getState,
};
}

combineReducers#

参数#

reducers#

  • Type: Object
  • Required

返回值#

rootReducer#

  • Type: Function

实现#

function combineReducers(reducers) {
let finalState = {};
return function reducer(state = {}, action) {
for (const key in reducers) {
if (Object.hasOwnProperty.call(reducers, key)) {
finalState[key] = reducers[key](state[key], action);
}
}
return finalState;
};
}

测试#

const { createStore } = require('redux');
function numReducer(state = { num: 1 }, action) {
switch (action.type) {
case 'increase':
return { ...state, num: state.num + (action.num || 1) };
case 'decrease':
return { ...state, num: state.num - (action.num || 1) };
default:
return state;
}
}
function nameReducer(state = { name: 'Tom' }, action) {
switch (action.type) {
case 'setName':
return { ...state, name: action.name || state.name };
default:
return state;
}
}
function combineReducers(reducers) {
let finalState = {};
return function reducer(state = {}, action) {
for (const key in reducers) {
if (Object.hasOwnProperty.call(reducers, key)) {
finalState[key] = reducers[key](state[key], action);
}
}
return finalState;
};
}
const store = createStore(combineReducers({ numReducer, nameReducer }));
store.subscribe(() => console.log(store.getState()));
const action1 = { type: 'increase', num: 2 };
const action2 = { type: 'setName', name: 'Lucy' };
const action3 = { type: 'decrease', num: 3 };
store.dispatch(action1); // { numReducer: { num: 3 }, nameReducer: { name: 'Tom' } }
store.dispatch(action2); // { numReducer: { num: 3 }, nameReducer: { name: 'Lucy' } }
store.dispatch(action3); // { numReducer: { num: 0 }, nameReducer: { name: 'Lucy' } }