应用程序的整个全局状态存储在单个store对象树中(单一共享数据存储)。改变状态的唯一方法是创建一个action(一个描述发生了什么的对象),并将它dispatch到store,编写纯reducer函数,该函数根据旧状态和动作计算新状态。
state
单一的全局数据源,所有状态都存储在单个树中,那么难以实现的状态管理会突然变得微不足道,该状态对外部只读
action
改变state的唯一方法是发出一个action(一个描述发生了什么的对象);所有的变化都是集中管理的,并且按照严格的顺序一一发生
reducer
纯函数,它接受前一个状态和一个动作,并返回下一个状态;返回的是新的状态对象,而不是改变以前的状态
store
保存应用程序状态树的对象。Redux应用程序中应该只有一个store,因为合并发生在reducer级别。
编写Redux
使用单例模式实现唯一的数据源
const createStore = (() => {
let store = null
const state = {}
const getState = () => { }
const dispatch = () => { }
const subscribe = () => { }
const unSubscribe = () => {}
const replaceReducer = () => { }
return () => {
if (!store) {
store = {
getState,
dispatch,
subscribe,
replaceReducer,
}
}
return store
}
})()
export default createStore
通过调用createStore(),可以拿到store,且多次调用生成的是同一个store,store里面包含了
dispatch(action)基本调度函数。getState()返回store的当前状态。subscribe(listener)注册一个在状态改变时调用的函数。replaceReducer(nextReducer)更换store的reducer以计算state、动态假装一些reducer、实现热重载
getState返回一个state的副本防止消费者直接修改其引用属性,使用lodash的cloneDeep方法来返回
const getState = () => {
return _.cloneDeep(state)
}
添加和移除订阅者
const listeners = [];
const subscribe = (fn) => {
listeners.push(fn)
}
const unsubscribe = (fn) => {
const index = listeners.indexOf(fn)
listeners.splice(index, 1)
}
通常使用闭包的方式将添加和移除放在一起,移除函数作为添加的返回值
const listeners = [];
const subscribe = (fn) => {
listeners.push(fn)
const unsubscribe = () => {
const index = listeners.indexOf(fn)
listeners.splice(index, 1)
}
return unsubscribe
}
初始化reducer并加入修改reducer的函数
let currentReducer = (state, action) => {
return state;
}
const replaceReducer = (reducer) => {
currentReducer = reducer
}
最后通过实现dispatch来完成订阅者消息的触发,防止修改到源数据,都使用数据的副本传递给消费者
const dispatch = (action) => {
const preState = _.cloneDeep(state)
state = currentReducer(_.cloneDeep(state), action)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener(preState, _.cloneDeep(state))
}
}
完整代码如下:
import _ from 'lodash'
const createStore = (() => {
let store = null
let state = {}
const listeners = []
let currentReducer = (state, action) => {
return state;
}
const getState = () => {
return _.cloneDeep(state)
}
const dispatch = (action) => {
const preState = _.cloneDeep(state)
state = currentReducer(_.cloneDeep(state), action)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener(preState, _.cloneDeep(state))
}
}
const subscribe = (fn) => {
listeners.push(fn)
const unsubscribe = () => {
const index = listeners.indexOf(fn)
listeners.splice(index, 1)
}
return unsubscribe
}
const replaceReducer = (reducer) => {
currentReducer = reducer
}
return () => {
if (!store) {
store = {
getState,
dispatch,
subscribe,
replaceReducer,
}
}
return store
}
})()
export default createStore
使用示例:
const store = createStore()
store.subscribe((prev, v) => console.log(prev, v, '第 1 个消费者'))
store.subscribe((prev, v) => console.log(prev, v, '第 2 个消费者'))
store.replaceReducer((state, action) => {
const { type, ...rest } = action
if (action.type === 'test') {
return {
...state,
...rest,
}
} else {
return state
}
})
store.dispatch({ type: 'test', value1: 'testValue1' })
store.dispatch({ type: 'test', value2: 'testValue2' })
store.dispatch({ type: 'other', value: 'other' })
有两个订阅者,在3次dispatch后都执行了reducer得到新的state结果