React 状态管理库深度对比:在做技术选型的时候如何选择合适的状态库,nolan出品
掘金链接:https://juejin.cn/post/7368288987642232872
1,简介
在状态共享这方面,不像 Vuex,React 的官方并没有强力推荐某种封装方案,所以 React 的状态管理工具五花八门,百花齐放,
react-redux、dva、Context API、mobx、recoil/Jotai、zustand,valtio.
其中就有:
做什么都要 dispatch 的 redux 流派,主打单向数据流,包括:react-redux 、dva、新星代表 zustand
响应式流派 mobx。以及新星代表 valtio ,以及一个很有特点的库 resso
原子状态流派。来自 facebook 开源的 recoil ,以及新星代表 jotai
完全体 hooks 流派。hox、reto、umijs@4 内置数据流,包括 Vue 官方推荐的新状态管理工具 pinia 也是这个流派。
2,为什么会考虑写这篇文章
在公司的项目中使用的是 dva.js 作为 状态管理,但是Dva.js在编写代码时过于臃肿,并且 dva.js 仓库在 2019 年开始就不再维护了,不能及时跟上最新的技术发展。其在 ts 不再都没有任何提示的问题也逐步暴露。更不用说dva.js在错误处理方面极其不优雅,dva.js 在处理错误时,往往会导致整个应用崩溃,而不是只影响出错的部分。这使得我考虑有没有一种更加优雅的方式进行React状态的管理,并且能够完美兼容项目中已有的状态管理方法,作为一种补充手段为开发提效。
并且随着技术不断发展,我们终归是要摆脱繁琐的 dva,寻找一个新的状态管理工具,来减少我们这一块的代码量,对于这块技术的探索就提上了日程
具体改造可以参考我写的这篇文章 https://juejin.cn/post/7321049446443384870?searchId=2024051008370556AFD9AB416FDEE1C534
最终我选择了使用 zustand 作为我们新的状态管理工具引入项目,为什么会选择这个呢,文章的末尾会给我我考虑的理由
3,市面上React状态管理库介绍
在 Web 前端开发中,状态管理是一个非常重要的话题。随着 React 生态圈的不断壮大,越来越多的状态管理工具应运而生。其中主要分为这几个流派:
1. Redux 流派
Redux 是最传统的状态管理库,强调单一数据源、不可变数据和纯函数更新。使用dispatch来触发action,通过reducers处理action并返回新的state。React-Redux提供了与React集成的桥梁。
Redux 的三大原则是:
单一数据源:整个应用的 state 被存储在一个 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
State 是只读的:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
使用纯函数来执行修改:为了描述 action 如何改变 state tree ,你需要编写 reducers。
在 React 生态圈中,有很多基于 Redux 思想的状态管理工具, 例如:
react-redux:
React-Redux 是一个在 React 应用中使用 Redux 的官方绑定库。它提供了一种在 React 组件中连接 Redux store 的方法,使得组件能够获取 store 中的 state 并触发 actions。
简单实用介绍:
npm install react-redux redux //安装依赖
store.js
import {
createStore } from 'redux';
// 定义初始状态
const initialState = {
count: 0 };
// 定义根reducer,它决定了状态如何随着actions而变化
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
// 当action类型为INCREMENT时,增加count
return {
...state, count: state.count + 1 };
default:
// 默认情况下不改变状态
return state;
}
};
// 使用createStore创建Redux store,并传入根reducer
export const store = createStore(rootReducer);
App.js
import React from 'react';
import {
Provider } from 'react-redux';
import store from './store';
import Counter from './Counter';
// React组件App使用Provider包裹,Provider是react-redux提供的组件,
// 它允许我们将Redux的store传递给组件树的任何部分
function App() {
return (
store}>
);
}
export default App;
Counter.js
import React from 'react';
import {
connect } from 'react-redux';
// mapStateToProps是一个函数,它将Redux store中的状态映射到组件的props
const mapStateToProps = state => ({
count: state.count });
// mapDispatchToProps创建了一个对象,对象中的每个函数当你调用它们时,
// 都会通过dispatch派发一个action,这些函数也会作为props传递给组件
const mapDispatchToProps = dispatch => ({
increment: () => dispatch({
type: 'INCREMENT' }),
});
// Counter是一个普通组件,它接收来自Redux store的count和increment作为props
function Counter({
count, increment }) {
return (
Count: {
count}
{
/* 当按钮被点击时,调用increment prop来dispatch一个INCREMENT action */}
);
}
// 使用connect高阶组件将Counter组件连接到Redux store
// connect函数接受两个参数:mapStateToProps和mapDispatchToProps
// 它返回一个新的组件,这个组件能够访问Redux store中的状态和分派actions
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
这段代码演示了Redux最基础的使用方式:创建store、定义reducer、使用Provider将store提供给组件树、以及使用connect将组件连接到Redux store。通过这种方式,React组件能够获取全局状态并触发状态变更。 特点:
提供了 Provider 组件,用于将 Redux store 传递给 React 组件树。
提供了 connect 高阶组件,用于将 Redux store 中的 state 和 actions 映射到组件的 props。
基于 React 的 context API 实现,避免了不必要的组件重新渲染。
优点:
官方维护,社区支持度高,有很多相关资源。
高性能,避免了不必要的组件重新渲染。
支持中间件,可以方便地扩展 Redux 的功能。
缺点:
学习曲线较陡峭,需要熟悉 Redux 的概念。
代码冗余,需要编写很多样板代码。在大项目的时候简直是灾难,基本不会怎么考虑
需要手动管理 state 更新逻辑。安装依赖:
dva:
受Redux启发,为中国开发者设计,提供简化版的API和模型(model)的概念,集成了Redux、Redux-Saga和React-Redux,使得状态管理更加简洁。
我认为 dva.js 更加适用于中小型的 React 项目,对于大型复杂的项目来说优点难受
首先,使用 npm install dva 安装 dva 依赖。
接下来,创建一个 Dva 应用(app.js):
// 导入 dva 核心库
import dva from 'dva';
// 初始化一个 dva 应用实例
const app = dva();
// 定义一个 model 来管理状态和逻辑,这里是计数器的模型
app.model({
// 命名空间,用于区分不同模块的 action 和 reducer
namespace: 'counter',
// 初始状态
state: 0,
// reducers 负责处理同步操作,更新 state
reducers: {
increment(state) {
// 返回新的 state,这里实现计数器加一的功能
return state + 1;
}
}
});
// 导出 dva 应用实例
export default app;
在应用中使用创建的 Dva 应用(App.js):
// 引入 React 和 dva 的 connect 函数
import React from 'react';
import {
connect } from 'dva';
// 引入初始化的 dva 应用实例
import app from './app';
// 定义 React 组件 Counter,展示计数器状态和提供增加按钮
function Counter({
count, dispatch }) {
return (
Count: {
count}
{
/* 点击按钮触发 action,通过 dispatch 方法 */}
);
}
// 映射 state 到 Counter 组件的 props
const mapStateToProps = state => ({
count: state.counter });
// 使用 connect 函数将 Counter 组件与 Redux store 连接起来
const ConnectedCounter = connect(mapStateToProps)(Counter);
// 配置路由,指定根组件为 ConnectedCounter
app.router(() =>
// 启动 dva 应用,并挂载到页面的 #root 元素上
app.start('#root');
在这个示例中,我们创建了一个简单的计数器应用。首先创建一个名为 counter