React状态管理工具---Redux、Redux Toolkit、Zustand(推荐使用)、Jotai、Recoil、MobX、Pinia

56 阅读5分钟

中心化状态管理

Redux

单一数据源、不可变数据和纯函数更新。使用dispatch触发action,通过reducers处理action并返回新的state。

Redux流程

  • 定义一个reducer函数(根据当前想要做的修改返回一个新的状态)
  • 使用createStore方法传入reducer函数生成一个store实例对象
  • 使用store实例的subscribe方法订阅数据的变化(数据变化,通知)
  • 使用store实例的dispatch方法提交action对象触发数据变化
  • 使用store实例的getState方法获取最新的状态数据更新视图

Redux示例:

安装
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 (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

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 (
    <div>
      <p>Count: {count}</p>
      {/* 当按钮被点击时,调用increment prop来dispatch一个INCREMENT action */}
      <button onClick={increment}>Increment</button>
    </div>
  );
}

// 使用connect高阶组件将Counter组件连接到Redux store
// connect函数接受两个参数:mapStateToProps和mapDispatchToProps
// 它返回一个新的组件,这个组件能够访问Redux store中的状态和分派actions
export default connect(mapStateToProps, mapDispatchToProps)(Counter);

总结:创建store、定义reducer、使用Provider将store提供给组件树、使用connect将组件连接到Redux store。

Redux使用环境、优缺点

  • 优点:
    • 单一的全局状态树,所有状态集中管理
    • 数据流方式清晰,使用action和reducers描述状态变化
    • 通过Middleware可以扩展功能(如redux-thunk和redux-saga)
  • 适用场景
    • 大型应用或复杂状态管理场景
    • 需要严格的状态管理流程,以及调试和扩展功能时

redux-toolkit

Redux Toolkit是Redux的简化版本,提供类似Pinia的模块化功能。

redux-persist(持久化数据存储)

背景
  • 使用redux来管理和存储全局数据的基础上,再去使用localStorage来读写数据,这样不仅是工作量巨大,还容易出错
  • 页面刷新,数据丢失

redux中异步的请求如何处理

使用两种中间件:redux-thunk、redux-saga

Zustand

zustand示例:

创建一个store文件,并创建一个index.ts文件
// store/index.tsx
// 安装zustand (npm install zustand)

import {create} from 'zustand'

export interface State{
 count:number
}
export interface Actions{
  increment:()=>void
  decrement:()=>void
}
// 使用create方法创建一个新的Zustand store
const useStore = create<State & Actions>((set)=>({
// 定义一个名为count的状态,初始值为0
  count:0,
  // 定义方法,用于更新count状态
  increment:()=>set((state)=>({ count:state.count + 1}))
  decrement:()=>set((state)=>({ count:state.count - 1}))
}))
export default useStore
在应用中使用创建的Zustand store
// App.js
import React from 'react';
import useStore from './store';

function Counter() {
  // 从 useStore 中获取 count 状态和 increment 方法
  const { count, increment } = useStore();

  return (
    <div>
      {/* 渲染 count 状态 */}
      <p>Count: {count}</p>
      {/* 当点击按钮时,调用 increment 方法更新 count 状态 */}
      <button onClick={increment}>Increment</button>
    </div>
  );
}

function App() {
  return (
    <div>
      {/* 渲染 Counter 组件 */}
      <Counter />
    </div>
  );
}

export default App;

Zustand执行流程:

  • 1:创建store:调用create函数生成一个store,这个 store 实际上是一个自定义的 React Hook,它基于 zustand 提供的 API 对象和 React 官方的 useSyncExternalStore Hook 实现。

  • 2:API对象:store 返回的 API 对象包含用于管理状态的几个关键方法:更新状态的 setState、获取状态的 getState、添加监听器的 subscribe,以及清除所有监听器的 destroy。

  • 3:状态 state:zustand 的状态由用户在创建 store 时定义的 createState 函数生成,当调用 create(createState) 时,state 初始化为用户自定义的初始状态。

  • 4:订阅的时机:subscribe 方法在 useEffect 内部执行,用于添加 listener。尽管没有显式调用 useEffect,zustand 通过 useSyncExternalStore 的内部机制实现了对状态变化的订阅和清理。

  • 5:状态更新与渲染触发:当调用 setState 更新状态时,zustand 会遍历所有已注册的 listener 并触发它们。每个 listener 实际上就是 handleStoreChange,它会检查前后状态是否变化,如果变化,则通过 useSyncExternalStore 触发组件重新渲染。

中间件

Zustand使用场景、优缺点

缺点: 状态管理:zustand的轻量级和直接的状态管理方式不适合需要严格区分状态逻辑和界面逻辑的项目

  • 特点:
    • 轻量级快速的状态管理解决方案,API简洁
    • 采用hooks的API,可以与其他React特性集成
    • 支持中间件,功能灵活
  • 适用场景:
    • 小型至中型应用,需求变化不大的场景下
    • 适合对性能要求比较高的场景,因为它会以最小的开销进行状态管理

响应式状态管理

MobX

MobX是一个响应式编程的状态管理库,自动追踪状态的变化并自动更新视图。

Mobx特点、适用场景

  • 特点:
    • 适用自动检测和反应式编程管理状态
    • 通过observable状态使得状态更新更加直观和简洁
    • 不需要像Redux那样明确描述所有状态变化
  • 适用场景
    • 适合希望以简洁和直观的方式进行状态管理的开发者
    • 比较复杂的应用,MobX的响应式特性能够极大提升开发效率

原子状态流

Recoil

适合处理复杂状态依赖和派生状态,Recoil更适合需要跨多个组件共享和管理全局状态的应用。