React状态库的选择Reducer,Redux,Mobx,Zustand?

280 阅读4分钟

自己写项目是尽量不用这些状态库, 一大堆的模板代码,配置环境都得半天,特别是redux, 虽然目前提供一系列脚手架redux-toolkit进行优化,但还是特别麻烦, 还有一个原因:就是项目开发初级阶段, 需求不断在迭代,状态设计不可能一次就好,总是需要来回重构.

跨组件状态传递的常用方法

状态库的引用主要是为了解决跨组件之间状态的传递,和数据的跟踪. 先梳理一些跨组件传递的方法

  1. 兄弟组件, 把状态抽取到父组件
  2. event emit / dom event
  3. localstore
  4. 参数通过url参数传递
    • 注意 参数编码
      const serialize = (obj) =>
        Object.entries(obj)
          .map((i) => [i[0], encodeURIComponent(i[1])].join("="))
          .join("&");
      
      参考 stackoverflow
    • encodeURIComponent() vs encodeURI
      后者会编译更多字符,如#号,一般都用 encodeURIComponent ,除A-Z a-z 0-9 - _ . ! ~ * ' ( )以外的所有字符都会被编译
  5. react中useState+useContext+useReducer 官网有完整示例

回顾一下项目开始阶段

  1. 我开始就是通过合理地设计组件和(1)状态向上抽取 来进行兄弟组件的状态传递.

  2. 跨页面组件的状态我是通过url(4)进行传递

  3. 一些不常变动的需要多个组件共用的状态我用loaclstore共享, 需要监听storage的变化, 特别是ahooks最新版本有提供一个现成的方法useLocalStorageState,当然以下方法都能达到状态传递的效果,值也是响应式的

    • useLocalStorageState
    • useSessionStorageState
    • useCookieState
  4. 也可以用event emit, ahooks也提供了一个方法

    • useEventListener
    import React, { useState, useRef } from 'react';
    import { useEventListener } from 'ahooks';
    
    export default () => {
      const [value, setValue] = useState(0);
      const ref = useRef(null);
    
      useEventListener(
        'click',
        () => {
          setValue(value + 1);
        },
        { target: ref },
      );
    
      return (
        <button ref={ref} type="button">
          You click {value} times
        </button>
      );
    };
    

    也可以自定义事件 CustomEvent

    useEventListener('set-token', () => {
        SetToken()
    })
      const tokenEvent = new CustomEvent('set-token', {
        detail: {}, // 如果有参数可以放在这咯
        bubbles: false,
        cancelable: false,
        composed: false,
    })
    tokenEvent(tokenEvent)
    
  5. 为了约束状态的统一入口,最后用(5)useState+useContext+useReducer重构. 但此时已经没必要了, 状态结构基本已经稳定, 可以找第三方框架来接管这些状态

第三方主流框架

redux

排除,感觉没必要
redux-toolkit能方便一点点, 大家可以自己去官网文档 redux-toolkit.js.org/api/getDefa…
github.com/reduxjs/red…
redux-toolkit.js.org/usage/usage…
react-redux.js.org/tutorials/t…

mobx

hooks存在闭包问题,大量hooks必然增大应用内存 其实 Hooks 这些问题都是因为没有一个公共的空间来共享数据导致的,在 Class 组件中,我们有 this , 在 Vue3 中,我们有 setup作用域 。Hooks 你只能依靠useRef + ref.current 来 hack 了。但它极其不优雅,

这时候你是不是也想到了我们的 Mobx ,它不就是提供统一作用域的神器吗, 之前只有class写法, 后来也推出了hooks的写法

在数据结构比较复杂的话,性能优于redux. 但项目中其实没那么多讲究, mobx和redux同样经典, 自己喜欢哪个就用哪个, 但redux太麻烦, 所以自己不喜欢用. 而且mobx对异步的处理比较友好,不需要引入其他中间件

mobx可以直接更新状态,但react要通过action和reducer更新状态

mobx只重新渲染受影响的组件 ,但react需要自己通过优化来实现高效渲染

react需要自己写大量的memo, useMemo,useCallBack去优化这个性能

mobx-react-lite requires React 16.8 or higher.

mobx.js.org/README.html mobx.js.org/react-integ…
www.npmjs.com/package/mob…

moxb中的一些使用和概念

  • observer
    Mobx 使组件响应数据状态的变化主要有以下三种方式:
  1. observer HOC
  2. Observer Component <Observer>{renderFn}</Observer>
  3. useObserver hooks

传统React.Component 中使用 mobx 时候 我们使用 observer HOC 的方式 ,它的主要能力是给类组件提供 pure component 的能力,可以将类组件的 props 和 state 转换为 observable 态,从而来响应数据状态的变化。 同样,这种 HOC 形式也可以直接在 Hooks 中正常使用。 但是 Hooks 并不推荐 HOC 的方式。于是乎就出现了 useObserver。

以上三种具体区别和场景使用如下
www.jianshu.com/p/c21907121… @NANAISNANA

  • useLocalObservabl 使用给定的属性、方法和计算值创建可观察对象。
    useLocalObservable是以下各项的简写:
    const [state] = useState(() => observable(initializer(), annotations, { autoBind: true }))

mobx和hooks的使用

Mobx autorun 原理解析

zustand

简单,功能也很强大,和ts集成也很方便, 也提供了相关hooks使用,推荐, 也不用像redux引入同步,异步的概念

github.com/pmndrs/zust…

stackoverflow.com/questions/6…
ahooks.js.org/zh-CN/hooks…