实现MyRedux系列
现在通过前边两部分,我们实现了一个通用的createStore
:
function createStore (state, stateChanger) {
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const dispatch = (action) => {
state = stateChanger(state, action) // 覆盖原对象
listeners.forEach((listener) => listener())
}
return { getState, dispatch, subscribe }
}
那他怎么用呢?
let appState = {
title: {
text: 'React.js',
color: 'red',
},
content: {
text: 'React.js 内容',
color: 'blue'
}
}
function stateChanger (state, action) {
switch (action.type) {
case 'UPDATE_TITLE_TEXT':
return {
...state,
title: {
...state.title,
text: action.text
}
}
case 'UPDATE_TITLE_COLOR':
return {
...state,
title: {
...state.title,
color: action.color
}
}
default:
return state
}
}
const store = createStore(appState, stateChanger)
...
其实可以优化一下,appStore
和stateChange
可以合并
function stateChanger (state, action) {
if (!state) {
return {
title: {
text: 'React.js',
color: 'red',
},
content: {
text: 'React.js 内容',
color: 'blue'
}
}
}
switch (action.type) {
case 'UPDATE_TITLE_TEXT':
return {
...state,
title: {
...state.title,
text: action.text
}
}
case 'UPDATE_TITLE_COLOR':
return {
...state,
title: {
...state.title,
color: action.color
}
}
default:
return state
}
}
stateChange
现在既充当了获取初始化数据的功能,也充当了生成更新数据的功能,如果传入了state
就更新数据,否则为初始化数据,那createStore
可以优化成一个参数,因为state
和stateChange
可以合并
function createStore (stateChanger) {
let state = null
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const dispatch = (action) => {
state = stateChanger(state, action)
listeners.forEach((listener) => listener())
}
dispatch({}) // 初始化 state
return { getState, dispatch, subscribe }
}
createStore
内部的 state
不再通过参数传入,而是一个局部变量 let state = null
。createStore
的最后会手动调用一次 dispatch({})
,dispatch
内部会调用 stateChanger
,这时候的 state
是 null
,所以这次的 dispatch
其实就是初始化数据了。createStore
内部第一次的 dispatch
导致 state
初始化完成,后续外部的 dispatch
就是修改数据的行为了。
stateChange
可以换一个名字,就叫他reducer
,不要问,问就是reducer
function createStore (reducer) {
let state = null
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const dispatch = (action) => {
state = reducer(state, action)
listeners.forEach((listener) => listener())
}
dispatch({}) // 初始化 state
return { getState, dispatch, subscribe }
}
reducer
createStore
接受一个叫reducer
的函数,他一定是一个纯函数,他接收两个参数,一个是state
,一个是action
他不能干任何事情,只能初始化和计算新的state
总结
从第一篇开始,首先发现如果共享的状态能被随意修改,那程序地行为会不可预料,所以我们要求只能通过dispatch
去进行数据修改,而且必须要在action
中声明,然后我们把它抽象出来成为一个createStore
,它能生产store
,里面有getState
和dispatch
让我们使用
后来发现每次修改数据都要重新渲染,而我们希望能够自动渲染视图,所以使用了订阅者模式,通过store.subscribe
订阅数据修改事件,为了让它自动渲染视图
在我们使用的时候发现每次都重新渲染视图会有很大的性能问题,所以使用共享结构的对象来解决问题,而后让stateChanger
更名为reducer
,并让他是一个纯函数,负责初始化state
,根据state
和action
计算具有共享结构的新state