最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 20行代码实现React全局状态共享

    正文概述 掘金(四路闲人)   2021-03-24   597

    最近在使用 redux 做项目时,发现其 connect , reducer 等写法十分让人苦恼。给我们带来便利的同时产生了大量的模板代码。虽然一些大佬觉得其设计非常有逻辑且易维护,但其大量的模板代码及设计思路确实会让一些人心烦意乱。我思考了一下,有没有办法可以跳过 dispath 直接修改其值就能更新视图,以及不使用 connect 注入直接 import 导入状态使用。于是我便朝着这个方向去尽可能的实现一个 react 全局共享状态的方法。

    首先全局共享即所有组件都可访问的数据,这个并不难。只需定义一个引用类型的数据,可以让其他组件访问到就行。例如:

     const stateModel = {
         count : 0
     }
    function App() {
       return (
       <div>
         {stateModel.count}
       </div>
       );
    }
    

    接下来就是修改数据更新视图了。要监听到对象的数据变化我首先想到了 Proxy。我们创建一个函数 observe。通过他实现数据的访问控制。

    function observe(state){
        return new Proxy(state,{
            set(target,key,value){
                // 组件即将更新
            }
        })
    }
    
    const stateModel = observe({
        count : 0
    })
    
    

    接下来就是更新组件了,目前更新 react 组件的方法有 通过父级的传过来的 props (目前大部分 react 状态管理都是这种方式 )、或者通过 context 、react hook 函数、或者是 react 类组件的 component.forceUpdate() 方法。考虑到日前使用 react hook 组件的人占大多数(我本人也习惯使用 hook组件)。我想通过 react hook函数实现状态更新。版本1的 observe函数来了。

    function observe(state){
        const [r,reflash] = useState(0);
        return new Proxy(state,{
            set(target,key,value){
                state[key] = value;
                reflash(r + 1);
                return true;
            }
        })
    }
    
    

    带入到 App 组件测试

      const stateModel = observe({
          count : 0
      })
     function App() {
        return (
        <div>
          {stateModel.count}
        </div>
        );
    }
    
    

    当我满怀期待的进行测试时,得到了 react 亲切的问候。

    20行代码实现React全局状态共享 小丑竟是我自己,我忘记了 hook 函数必须在函数组件中才能被调用。所以我修改了策略。调用 observe时返回一个包含 hook 函数的函数。

    function observe(state){
        return ()=>{
             const [r,reflash] = useState(0);
            return new Proxy(state,{
                set(target,key,value){
                    state[key] = value;
                    reflash(r + 1);
                    return true;
                }
            })
        }
    
    }
    
    

    再在 app 组件中执行。

    const stateModel = observe({
      count : 0
    })
    function App() {
        const state = stateModel()
        return (
        <div>
          {state.count}
          <button onClick={()=>state.count++}>add count</button>
        </div>
        );
    }
    

    测试成功 !!!!。目前点击增加 count 没问题。那么是否就真的没问题了呢。看文章接下来的字数就知道没这么简单。我们尝试把 add 按钮单独放入一个组件。

    function App() {
        const state = stateModel()
        return (
        <div>
          {state.count}
          <AddBtn/>
        </div>
        );
    }
    const AddBtn = ()=>{
        const state = stateModel()
        return <button onClick={()=>state.count++}>add count</button>
    }
    

    测试你会发现,count 无法正常的增加。发生甚么事了,为什么何在一起可以分开就不行了呢。这是因为你每次调用 stateModel 就会返回不同的 new Proxy,App 组件的 state 和 AddBtn 组件的 state 看视一样实则完全是不同的两变量。AddBtn 中的 state 发生改变无法影响App 组件的 state。那么我们要让他们是同一个人。所以版本3诞生了。

    const observe = (state)=>{
        const reflashs;
        const stateProxy = new Proxy(state,{
            set(target,key,value){
                state[key] = value;
                const [r,reflash] = reflash;
                reflash(r + 1);
                return true;
            }
        })
        return ()=>{
            reflashs = useState(0)
            return stateProxy
        }
    }
    
    

    再次测试,发现 count 还是没有增加。再仔细看代码,直接对自己说句我是撒比。对呀之前的new Proxy 返回的不是同一个地址。这次 useState 返回的也不是同一个 hook 函数,这样他也无法更新其他组件。再次修改得到最终版本。

    const observe = (state)=>{
        const reflashMap = new Map();
        const stateProxy = new Proxy(state,{
            set(target,key,value){
                state[key] = value;
                for(const [r,reflash] of reflashMap.values()){
                    reflash(r+1);
                }
                return true;
            }
        })
        return (key)=>{
            reflashMap.set(key,useState(0))
            return stateProxy
        }
    }
    
    function App() {
        const state = stateModel('App')
        return (
        <div>
          {state.count}
          <AddBtn/>
        </div>
        );
    }
    const AddBtn = ()=>{
        const state = stateModel('AddBtn')
        return <button onClick={()=>state.count++}>add count</button>
    }
    
    

    16行代码实现 observe 函数 react 全局状态共享。其中 reflashMap 用于存储每个组件的 key 及对应的渲染函数,这个 key 可以调用stateModel时传进来,每个组件拥有不同的 key。这篇文章我不仅讲了其实现原理,也讲了我实现的过程,只是希望大家也能多思考每一步代码究竟是怎么来的。 我沿着这个思路,再进行优化及添加了一些功能,开源了一个工具。 地址:https://www.npmjs.com/package/erwin


    起源地下载网 » 20行代码实现React全局状态共享

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元