redux的学习实现第四课:将stateChanger改名为reducer,不要问为什么的reducer
优化createStore的内容
上一节我们写的stateChanger是这个样子的:
function stateChanger(state, action) {
switch (action.type) {
case 'CHANGE_TITLE':
return {
...state,
title: {
...state.title,
text: action.text
}
};
case 'CHANGE_TITLE_COLOR':
return {
...state,
title: {
...state.title,
color: action.color
}
};
case 'CHANGE_CONTENT':
return {
...state,
content: {
...state.content,
text: action.text
}
};
case 'CHANGE_CONTENT_COLOR':
return {
...state,
content: {
...state.content,
color: action.color
}
};
default:
return state
}
}
其实,我们可以将stateChanger写入stateChanger中,将初始化state的工作直接交给stateChanger,react小书的作者是这么做的:
if(!state) {
return {
title: {
text: '我是标题',
color: 'red'
},
content: {
text: '我是内容',
color: 'blue'
}
};
}
将上述代码添加到stateChanger的开头,这样一来,即使我们没有要更新state,也可以通过不输入state的方式,返回初始化的appState,顺便此处已经可以将原来的appState常量注释掉了。
这样我们可以优化 createStore 成一个参数,因为 state 和 stateChanger 合并到一起了。
function createStore(stateChanger) {
let state = null;
let listeners = [];
const getState = () => state;//初始化/获取state的函数
// 订阅事件
const subscribe = (listener) => {
listeners.push(listener);
};
const dispatch = (action) => {
state = stateChanger(state, action);
//每一次在执行完stateChanger之后就将事件队列里的监听事件执行处罚
listeners.forEach((listener) => listener());
};
return { getState, dispatch, subscribe };
}
最开始照着代码去敲的时候,我以为上述代码就可以运行了,但是却意外的报错了,于是就开始艰难的排查,最后发现,上述代码中,将state的初始化交给了stateChanger,但是却没有将初始化的state替换出来,这就直接导致,我们第一次调用renderApp函数的时候找不到初始化appState,于是进行修改,如下:
function createStore(stateChanger) {
let state = null;
let listeners = [];
const getState = () => state;//初始化/获取state的函数
// 订阅事件
const subscribe = (listener) => {
listeners.push(listener);
};
const dispatch = (action) => {
state = stateChanger(state, action);
//每一次在执行完stateChanger之后就将事件队列里的监听事件执行处罚
listeners.forEach((listener) => listener());
};
dispatch({});// 初始化一次,保证getState能够将初始化的state返回
return { getState, dispatch, subscribe };
}
其中dispatch({})
这句代码至关重要,这让我们在调用store.getState()的时候可以直接获得初始化的state。
此时,我们将createStore的参数stateChanger改名为reducer,并且我们会发现reducer其实是个纯函数,我们传入state,就重新复制一份数据,并修改新的数据,原来传入的数据原封不动,如果我们不传入state,就返回一份初始化的state。
react小书中有这么一段话:
reducer 是不允许有副作用的。你不能在里面操作 DOM,也不能发 Ajax 请求,更不能直接修改 state,它要做的仅仅是 —— 初始化和计算新的 state。
所以总结一下,我们之前创建一个redux的套路就是:
// 定一个 reducer
function reducer (state, action) {
/* 初始化 state 和 switch case */
}
// 生成 store
const store = createStore(reducer)
// 监听数据变化重新渲染页面
store.subscribe(() => renderApp(store.getState()))
// 首次渲染页面
renderApp(store.getState())
// 后面可以随意 dispatch 了,页面自动更新
store.dispatch(...)