各类React状态管理工具介绍 | 青训营笔记

226 阅读5分钟

各类React状态管理工具介绍 | 青训营笔记

1、Local State(props)

顾名思义,就是组件级别的局部状态:

import {useState} from 'react'
const Hello = () => {
    const [name,setName] = useState('Jony')
    return <>Hello,{name}</>
}

这个local State只能在当前的Hello组件中生效,当组件创建时初始化和生效,组件销毁时失效。

之所以它也能被称为状态管理,是因为我们可以通过props进行层层传递来达到共享的效果,这是最繁琐的一种方式。

但同级组件之间不能使用props怎么办呢?

我们可以将localState向上提一级,包裹要传递状态的两个组件,通过这个父组件来实现他们之间的状态互通

但这终究不是长久之计,如果组件之间差的层级太多,这个方法就不太实用了。

为解决这个问题,我们引出React本身提供的Context:

2、Context

Context就像是一个单独的数据库一样,所有组件都可以从其中读取和写入数据,这样就达到了状态全局共享的目的

创建及注入:

render() {
    return (
    //使用Provider进行context全局注入
    //这里的value表示对context重新赋值
        <GlobalContext.Provider value={{name:'scw1',onClick:this.handleClick.bind(this)}}>
            <B />
        </GlobalContext.Provider>
    )
}

使用:

render() {
    return <GlobalContext.Consumer>
        {(globalContext)=>
         //消费Context的数据
            <span onClick={globalContext.onClick}>
                {globalContext.name}
​
            </span>
        }
    </GlobalContext.Consumer>

Context的问题:

  1. Context相当于全局变量,难以追溯数据的变更情况
  2. 使用Context的组件内部耦合度太高,不利于组件的复用和单元测试
  3. 会产生不必要的更新(会穿透memo和dependencies等)
  4. Context只能存储单一值,无法存储多个各自拥有消费者的值的集合
  5. 粒度也不好控制,不能细粒度的区分组件依赖了哪一个Context
  6. 多个Context会存在层层嵌套的问题

一些简单的数据,比如主题、语言等设置不会频繁的去变更,就可以放在context中进行保存

3、Flux

是Facebook官方给出的应用架构,利用单向流动的形式对公共状态进行管理,不过现在Flux已经被淘汰了,不过其设计思想还是可以参考和借鉴的

架构图:

flux.png

  • view:视图层
  • Action:视图发出的消息
  • Dispathcer:派发者,用来接收Action,执行回调函数
  • Store:数据层,存放状态,一旦发生改动,就会更新数据以及emit相关事件等

因为它耦合的层级比较深,所以redux诞生没多久就将其替代了

4、Redux

Redux从Flux演变而来,由于提出年份较早,不可避免地要兼容类组件写法,导致了其本身较重一些

架构图:

redux.png

Redux首先解构了Action和Dispatcher,使Action独立出来,不像Flux中Action需要和Dispatcher耦合在一起

遵循三大原则:

  • 单一数据源
  • Store中的state只读
  • 使用纯函数来执行修改

正是因为上述的特性,使得Redux可以做时间旅行,可以让应用程序切换到任意时间的状态。因此,如果复杂的场景,特别是存在页面组件间复杂的通信的场景,就非常适合使用Redux来管理状态!

但Redux的缺点也很明显:

  • 为实现纯函数的Reducer,Redux必须处理各种各样的副作用,需要引入一系列的副作用中间件,加重了心智负担
  • Action、Dispatch、Reducer的模式需要写过多的样板代码,增加了复杂度

因此中小型项目,不太推荐使用Redux

5、Mobx

Mobx通过透明的函数响应式编程使得状态管理变得简单和可扩展,设计和vue较为相似,是一个响应式的状态管理库

mobx.png

Mobx借助于装饰器的实现,使得代码更加简洁易懂。由于使用了可观察对象,所以Mobx可以做到直接修改状态,而不必像Redux一样编写繁琐的actions和reducers

优点:

  • 上手简单,可以直接修改状态不需要编写繁琐的actions和reducers

缺点:

  • 不能实现时间旅行和回溯,不适合前端数据流比较复杂的场景

随着React hooks,比如UserReducer等,以及原子型状态管理工具Recoil的发展。Mobx的的使用场景已经越来越小。

6、Recoil

Recoil一定程度上解决了Local State和Context的局限性,且能够兼容React的新特性,比如Concurrent模式等。

其解决的问题:

  1. 组件间的状态共享只能通过将state提升至它们的公共祖先来实现,但这样做可能导致渲染一颗巨大组件树
  2. Context只能存储单一值,无法存储多个各自拥有消费者的值的集合

Recoil更加的具有原子性,其中的状态都是Atom,可以任意组合,如下红色的是需要重新渲染的:

RecoilVSContext1.png 如果我们使用context:

RecoilVSContext2.png

使用Recoil渲染量一下子就少了很多

7、Zustand

Zustand是主打轻量级的状态管理工具,没有Redux那样臃肿的设计,也没有React类组件的历史包袱,它的体积很小,因此很适合做移动端网页

且Zustand的使用极其简单,在初始化的过程中,我们不仅能保存状态,也能在初始化的时候制定方法和函数