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 基本模型就做好了, 有什么不懂的可以提问哟~
来源: https://juejin.im/post/5b751e77518825533f45e267