redux状态管理器,实质上就是一个单例模式。我们来实现一个简单的redux模型,实现之前我们要先熟悉它的用法。
- Redux是将整个应用状态存储到到一个地方,称为store里面保存一棵状态树(state tree)
- 组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件
- 其它组件可以通过订阅store中的状态(state)来刷新自己的视图.
下面我们按照这个思想来想想怎么做。 我们来抽象一下,提取出最核心的思想,动用鬼斧神工画个图:
用文字来描述一下,一个唯一的仓库里,有一个私有属性state,仓库由门卫大哥进行管理,所有对state的操作都要经过门卫大哥,外面的人无权直接对state进行操作,如果有进行订阅,则在状态改变后收到状态改变事件。好了,我们按照这个思想来开始code吧
第一步:声明一个对象
const state={ a: 1 }
第二步:将对象包裹起来,使其不可随意访问
function createStore(){ const state={ a: 1 } }
第三步:暴露出一个方法,使外部可以对状态进行操作
function createStore() { let state={ a:1 }; function getState() { return state //此处直接将state返回,会使state引用地址暴露,从而被引用对象改变值 } return { getState } } let store = createStore() // 创建一个仓库 let state = store.getState() // 获取状态state console.log(store.getState()) // 输出{ a: 1 } state.a = 2 //将state a的值设置为2 console.log(state) // 输出为{ a: 2 } console.log(store.getState()) // 此时仓库中state的值也改变了,输出为{ a: 2 }
所以我们将第六行 return state
替换为 return JSON.parse(JSON.stringify(state))
可以避免这个问题。
第四步:除了获取状态我们还需要操作状态,暴露第二个方法,dispatch,顺便将state的初始化进行一下优化
'use strict' function createStore() { let state; function getState() { return JSON.parse(JSON.stringify(state)) } function dispatch(action) { // 分发 state = reducer(state,action) // 接收当前 State 和Action作为参数,返回一个新的 State } dispatch({ type: '@@INIT' }) // 在创建仓库的时候,初始化state的值 return { getState, dispatch } } let initState = { count: 0 } //处理器,接收二个参数 ,接收老状态和action,返回新状态 function reducer(state = initState, action) { // 如果state没有值,默认值为initState //判断动作的类型 switch (action.type) { case 'ADD_TODO': return { ...state, count: action.number }; //...state解构state所有属性,count: action.number覆盖前面的值 default: return state; } } let store = createStore() // 创建一个仓库 let state = store.getState() // 获取状态state let action = { type: 'ADD_TODO', number: 1 }; store.dispatch(action); // 派发一个action,改变state的状态 console.log(store.getState()) // 输出{ count: 1 }
diapatch中执行我们定义的reducer处理器函数,增删改查。例子演示了先创建一个仓库,在创建新仓库的时候初始化了state。然后diapatch一个action:ADD_TODO,执行的处理是改变count的值,返回一个新的state对象,最后我们可以看到输出,原来的state在初始化后变成{ count: 0 },又在ADD_TODO后变成了{ count: 1 }。
reducer函数是我们在使用redux时需要自己定义的处理函数。
至此,我们已经实现了创建一个仓库,并且可以自定义一些处理函数对state进行操作。还缺了什么呢?在实际项目中,状态改变后我们的大部分的组件需要立即得到新的状态,然后根据状态改变作出不同的处理。也就是说组件对state进行一个监听,一旦state发生改变,立马通知到对应的组件。让我们来继续实现吧。。。
第五步:增加一个订阅功能subscribe
function createStore() {
let state;
let listeners = [];
function getState() {
return JSON.parse(JSON.stringify(state))
}
function dispatch(action) { // 分发
state = reducer(state,action); // 接收当前 State 和Action作为参数,返回一个新的 State
listeners.forEach(listener => listener()) // 一旦状态改变,触发所有的监听函数,这里需要优化,只有相关状态改变才需要触发
}
function subscribe(listener){ // 订阅,如果需监听状态变化,将监听函数传过来
listeners.push(listener); // 保存监听函数到监听数组
return function () { // 返回取消订阅的函数
listeners = listeners.filter(item => item != listener); // 过滤监听函数
}
}
dispatch({ type: '@@INIT' }); // 在创建仓库的时候,初始化state的值
return {
getState,
dispatch,
subscribe
}
}
/*这里是分割线,上面一部分是仓库定义,下面部分是使用方法*/
let initState = {
count: 0
}
//处理器,接收二个参数 ,接收老状态和action,返回新状态
function reducer(state = initState, action) { // 如果state没有值,默认值为initState
//判断动作的类型
switch (action.type) {
case 'ADD_TODO':
return { ...state, count: action.number }; //...state解构state所有属性,count: action.number覆盖前面的值
default:
return state;
}
}
let store = createStore() // 创建一个仓库
let action = { // 定义一个action
type: 'ADD_TODO',
number: 1
};
let unADD = store.subscribe(function(){ // 监听状态改变
console.log('状态改变了,现在的state为:') // 状态改变了,现在的state为:
console.log(store.getState()) // { count: 1 }
})
store.dispatch(action); // 派发一个action,改变state的状态
复制代码
铛铛铛~,我们的redux基本模型就做好了,有什么不懂的可以提问哟~