最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 没有 Redux,让全局数据更简单

    正文概述 掘金(MoonBall)   2021-02-05   448

    笔者是一个有5年开发经验的前端工程师。从接触前端就一直使用 Redux,对 Redux 也算有点心得。今天分享个小 Tip 给大家 ?。

    慢慢臃肿的 Redux Store

    从欣赏到慢慢嫌弃

    Redux 的存在让前端开发变得简单,这点毫无疑问,否则也不会有那么多人用它。在项目初建时,Redux 中只有一两个全局状态,一切看起来都很舒服。

    但是,慢慢地,页面复杂起来了。页面A中有个状态在多个组件中需要复用。

    一把梭,几下复制粘贴就把这个状态放到 Redux Store 中了。暗笑:Redux 真棒。

    很快,页面B也有状态需要多个组件共用了。不用想,直接梭它。

    页面A、页面B又来了,页面C也来了。梭梭梭....

    Store 就成这样了。

    没有 Redux,让全局数据更简单

    好丑,好难过,不过问题不大。

    在某个周一的上午,迎来了新的需求,需要页面 B 能访问并修改 pageA.A1.A1A 中的数据。

    一把梭,在页面 B 中写上 state => state.pageA.A1.A1A,再调用修改 pageA 的相关 action。虽然完美实现了需求,但是每次看到这段代码,总觉得不舒服。它们不但丑(因为数据链路长),还别扭(因为 pageB 访问了 pageA 中的数据)。

    也许是我用法不对

    开始反思,是否有更好的解法。于是开始重新组织数据的结构,开启平铺模式。

    没有 Redux,让全局数据更简单

    甚至觉得按照页面来组织 store 不优雅,应该按照领域模型来组织,将所有数据都平铺了。

    没有 Redux,让全局数据更简单

    不得不说,全部平铺还是很有优势的,访问是路径变短了,状态只跟领域模型有关,与页面无关了。除了命名上麻烦点。

    这也是 dva 的 store 只有一层 model 的原因。但实际情况并没有变理想,多数时候一个 model 中有很多不相关的 state,比如复用后端某个接口的返回值。

    找到根本原因

    将状态放在 Redux Store 中,需要如下几步:

    1. 写好 model,将它注册到 store 中。注册到 store 的文件开始冗长,经常要解决冲突 ?。
    2. 访问 store 中的数据,需要不断的 state.A.B,如果没有类型文件链路长了容易出错。
    3. 更新某个状态调用,dispatch('updateA_B'),关键是这里的 type 是一个字符串。rematch 解决了这个问题。

    想想如果不用把状态集中放到一个 store 中,而只将它存放在模块级别。访问数据时只需引入该模块暴露的 store,修改数据时只需调用该模块暴露的方法。这个模块想放哪就放哪,不用集中放在 Redux Store 目录。

    尝试新的工具 use-global-hook

    仓库地址:use-global-hook

    基本用法

    使用时只需新建一个文件存放 model,参考官网 Example。

    import React from 'react';
    import globalHook from 'use-global-hook';
    
    const initialState = {
      counter: 0,
    };
    
    const actions = {
      addToCounter: (store, amount) => {
        const newCounterValue = store.state.counter + amount;
        store.setState({ counter: newCounterValue });
      },
    };
    
    export const useGlobal = globalHook(React, initialState, actions);
    

    然后在需要复用该状态的组件中,只需引用该 model 即可。import React from 'react';

    import React from 'react';
    import { useGlobal } from './useGlobal';
    
    const App = () => {
      const [globalState, globalActions] = useGlobal();
      return (
        <div>
          <p>
            counter:
            {globalState.counter}
          </p>
          <button type="button" onClick={() => globalActions.addToCounter(1)}>
            +1 to global
          </button>
        </div>
      );
    };
    
    export default App;
    

    通过 mapState 性能优化

    参考:官方例子

    通过 Immer 简化状态更新

    参考:官方例子

    通过暴露 getState 处理多个 model 存在依赖更新

    没有官方例子,属于个人总结。先给每个 model 都增加一个 action,其代码如下。

    function getState(store) { return store.state; }
    

    modelB 更新依赖最新的 modelA 的值。

    function useHandleAB() {
      const [stateA, { updateA, getState: getStateA }] = useModelA();
      const [stateB, { updateB }] = useModelB();
    
      return function handleAB(opts) {
        updateA(opts);
        // 此时 stateA 已经不等于 getStateA() 了
        updateB(getStateA(), opts); // 更新 modelB 依赖 modelA 的值
      };
    }
    

    总结

    Redux 的状态集中管理,其缺点有:

    1. 其 reducer 的组织方式一直有争论,原因就是集中式的管理导致 Store 变得冗长。
    2. 需要将所有状态进行注册,访问时又需要从 state 中取出。
    3. actionType 字符串的存在。

    use-global-hook 通过将模型 store 存在模块级别。其模块位置可以随意放置,更灵活。省略了状态注册和取出,更简介。其 actions 也是以普通方法存在,更自然。


    起源地下载网 » 没有 Redux,让全局数据更简单

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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