redux之createStore方法底层封装模拟

Posted cq1715584439

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redux之createStore方法底层封装模拟相关的知识,希望对你有一定的参考价值。

  首先在看代码之前让我们一起回顾下redux的思想吧   首先redux就是一个MVC思想的框架,他总体是遵循数据的单向流动自顶向下流动

在我们仓库中有一个initState用来存储着我们的初始数据 另外还有个actions这个用来进行一些变量的改变和传递 也就是MVC结构中的C---控制层

另外里面的reducer是对应着MVC中M层 用来进行逻辑的处理  注意这里的逻辑处理不能操作UI逻辑也就是直接控制视图的变量

  当我们用户想要改变数据的时候必须触动actions让其去操作reducer然后进行数据的改变,而不能让用户直接去操作我们state中的数据

  获取数据的时候也是同理 不能让其对数据库直接操作

先介绍下redux的使用  代码如下

技术图片
 1 //引入redux中创建仓库的方法
 2 
 3 import createStore,combineReducers from "redux";
 4 
 5 
 6 const initState=
 7     num:0
 8 
 9 
10 
11 
12 let reducer=(state=initState,action)=>
13    
14     switch (action.type) 
15         case "BIG":
16             state=action.data
17             return state;
18     
19         default:
20             return state;
21     
22 
23 
24 
25 
26 const reducers=combineReducers(reducer)
27 
28 const store=createStore(reducers);
29 export default store;
View Code

这是仓库的一些写法,而我们使用的时候   引入store 直接 调用下面这个方法

store.dispatch(type:"LIST_ADD",list:[1,2,3])  
获取值要放在订阅模式中  防止仓库改变但是页面不能同步更新 所以此时发布订阅模式就派上了用场
store.subscribe(()=>
this.setState(
hello: store.getState()
)
)

  以上介绍的是redux中的使用,下面是模拟这个效果进行的封装
先展示一个简单版
技术图片
 1 class Flux
 2     constructor(opj)
 3         //将接受到的这个对象挂载到这个class实例上
 4         Object.assign(this,opj)
 5         this.arr=[]
 6     
 7     getState(attr)
 8         //这里接受到的这个attr是让用户想取哪个值
 9         //这个方法是暴露给仓库的一个获取仓库数据的方法
10         if(attr)
11             return this.reducer(this.state,)[attr]
12         else
13             return this.reducer(this.state,)
14         
15     
16     dispatch(actionType)
17         //这里接受到的是一个对象
18         //console.log(this.state,"封装的方法")
19         //将最新的state获取出来保存起来  然后下次再调用getState方法的话就不会
20         //在读取默认值了
21         this.state=this.reducer(this.state,actionType)
22 
23         //当用户修改值得时候我们每次发布一下
24         this.promulgator("storeChange")
25     
26     subscriber(cb)
27         //订阅者   将订阅函数储存在事件队列中
28         this.arr.push(cb)
29     
30     promulgator()
31         //发布者 触发订阅者中的函数
32         this.arr.forEach(cb=>
33             cb()
34         )
35     
36 
37 
38 export default Flux;
View Code

看完上述的方法不知道大家有没有发现什么问题 

  在外面其实可以通过实例访问到里面state和reducer   既然能够访问到那么就证明使用者可以不通过我们规定的方法去直接修改数值

这样就与我们封装的数据单向流动 每次用户想要改变数据必须通过actions找到对应的reducer去修改的初衷了,所以我们需要对其进行一些

改正 让调用这个方法的时候只能通过我们暴露给用户的方法去改变,而不应该有其他的接口存在

 

具体改正如下

let state=Symbol("state")

//因为我们不能将this上暴露出state 不然用户可以访问到 所以这里要用到Symbol



class Flux
    constructor(opj)
        //将接受到的这个对象挂载到这个class实例上
        //Object.assign(this,opj)
        //不能用Object.assign的原因是因为state不能暴露在这个实例上
        //防止用户的修改

        this.reducer=opj.reducer;
        this[state]=opj.state

        this.arr=[]
    
    getState(attr)
        //这里接受到的这个attr是让用户想取哪个值
        //这个方法是暴露给仓库的一个获取仓库数据的方法
        if(attr)
            
            return this.reducer(this[state],)[attr]
        else
            //加三个点的作用是让用户只读不能改
            //还有一个方法 Object.getOwnPropertyDescriptor(this.state)
            //里面某个属性设置成false就不能改了
           
            return ...this.reducer(this[state],)
        
    
    dispatch(actionType)
        //这里接受到的是一个对象
        //console.log(this.state,"封装的方法")
        //将最新的state获取出来保存起来  然后下次再调用getState方法的话就不会
        //在读取默认值了
        this[state]=this.reducer(this[state],actionType)

        //当用户修改值得时候我们每次发布一下
        this.promulgator()
        //这个发布订阅的作用是为了防止数据改变用户得不到 也就是将视图和用户连接起来
    
    subscriber(cb)
        //订阅者   将订阅函数储存在事件队列中
        this.arr.push(cb)
    
    promulgator()
        //发布者 触发订阅者中的函数
        this.arr.forEach(cb=>
            cb()
        )
    


export default Flux;

 

具体使用方法如下  基本同redux一样

 1 import Store from  "../tool/index"
 2 
 3 let initState=
 4     num:1
 5 
 6 
 7 export let actions= 
 8     addNum(text)
 9         return 
10             type:"ADDNUM",
11             text
12         
13     
14 
15 
16 let reducer=(state=initState,action)=>
17     switch (action.type) 
18         case "ADDNUM":
19             let num=state.num+1
20             
21             return ...state,...num
22         
23         default:
24 
25             return ...state;
26     
27 
28 
29 //引入我们封装的flux框架 然后将reducer传入 并且将action传入
30 
31 //注意这里接受的是对象
32 export default new Store(
33     reducer,
34     state:initState
35 )

 

 

以上是关于redux之createStore方法底层封装模拟的主要内容,如果未能解决你的问题,请参考以下文章

redux教程之源码解析createStore

redux中createStore方法的默认参数

我可以在组件中使用redux中的createStore()吗?

redux初识

Redux原理探索

混淆 createStore 在 redux 中的工作方式