zoukankan      html  css  js  c++  java
  • 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 })
  • 相关阅读:
    selenium学习笔记05-selenium操作from表单
    selenium学习笔记04-webdriver核心方法的属性和使用
    selenium学习笔记03-selenium webdriver工作原理
    selenium学习笔记02-selenium定位的八大方法
    selenium学习笔记01
    微服务质量保证学习笔记(一)
    pytest,setup和teardown
    pytest用例编写规则、执行测试
    速耀达账套备份与恢复(速达二次开发)
    速耀达系统权限设置(速达二次开发)
  • 原文地址:https://www.cnblogs.com/cq1715584439/p/11116703.html
Copyright © 2011-2022 走看看