状态管理库选型
🗒️状态管理库选型
react|2023-6-14|最后更新: 2024-1-30
type
status
date
slug
summary
tags
category
icon
password
Blocking
Blocked by
top
URL
Sub-item
Parent item

本质

状态管理库简单理解为全局变量(虽然不是很恰当),可以在任意地方进行状态的读取和修改。
而一个完善的状态管理库需要考虑的点:
  1. render颗粒度。
  1. 异步修改。
  1. 派生状态。
  1. 是否支持非react组件内的状态操作。
  1. 是否支持中间件扩展。

原生问题

系统自带的Provider + Context(useContext)
一个完整的例子

用法

context 可以实现基础的状态共享。步骤:
  1. 通过createContext创建一个Context,并设置默认值。
  1. Context 中的值都在 Provider 的作用域下有效。所以在最外层包一个 Provider,value中设置传递值。
  1. 如果子组件需要时,则通过 React.useContext拿到Context值。

缺点

  • 重复渲染,性能差
当 Context 中的某个属性发生变化时,所有使用该 Context 的子组件都会被重新渲染,即使某些组件可能并未使用到这个属性。
这种问题有两种解决方法:
  1. React.memo 和 shouldComponentUpdate 这两种方式来解决。
  1. 将一个大型的 Context 拆分成多个小的 Context,可以精细地控制每个 Context 的更新,从而减少整个应用程序的重新渲染次数,提高性能和用户体验。
  • 数据变更方法难以维护
为了保证数据变更方法的可维护性与 action 的不变性,有两种方法但各有问题:使用自定义 hooks,但为了不会重复渲染,每个修改方法需要使用useCallback,需要声明依赖,会造成极大的心智负担。使用useReducer,不支持异步函数、不支持内部的 reducer 互相调用,不支持和其他 state 联动(比如要当参数传进去才可用)。
  • 使用范围限制
context的store只能在react中使用,无法在外部函数使用,例如请求函数中需要store中的属性,不能直接在请求函数中调用,就只能通过react中作为参数传递。
  • 无法处理异步请求。
对于异步的逻辑,Context API并没有提供任何API,需要自己做封装。
  • 无法处理数据间的联动
Context API并没有提供API来生成派生状态,同样也需要自行去封装一些方法来实现。

各状态库评测

 
各状态库下载趋势

流派总结

  • 没有状态管理工具:直接用 props 或者 context
  • 单项数据流:reduxzustand
状态是由一个单一的“源”(通常称为“store”)管理的,并通过将状态从store传递到子组件,然后再将子组件的“actions”传递回store来更新状态。
  • 双向绑定:mobxvaltio
内部对通过 state 绑定的组件,添加到了订阅者队列,store中的属性相当于一个被观察者,当属性状态变更后,通知所有订阅了该数属性的组件进行更新。
  • 状态原子化:jotairecoil
状态被分解成多个不可分割的小状态,并且通过原子操作的方式来更新这些小状态。

状态库对比

 
框架
流派
学习成本
派生状态(带缓存)
组件外调用
性能
异步支持
hooks context
Context
不支持
支持
友好
react-redux
单项数据流
不支持,需要中间件
支持
中等
复杂
zustand
单项数据流
不支持,需要中间件
支持
中等
友好
mobx
双向绑定
支持
支持
友好
valtio
双向绑定
不支持,需要中间件
支持
友好
jotai
状态原子化
支持
不支持
中等
友好
recoil
状态原子化
支持
不支持
中等
友好
 
 

总结

  • 简单项目使用useState + Context,会存在重复渲染的性能问题。
  • 复杂项目使用zustand,支持react组件外引用,但性能优化需要手动处理。
  • 高性能需求项目使用Valtio,基于 proxy 的方案,提供全自动的渲染优化。
 

参考文档

styled-components包装泛型组件代码转换babel、SWC、ESBuild
Loading...