序章、适用场景
-
在复杂度很低的场景下,我们完全可以用 Context 和
useReducer
来实现简单的状态管理,但它需要配合memo
或者PureComponent
来控制更新粒度。 -
在复杂度一般的场景下,可以尝试用 Recoil/jotai、hox 来管理分散的状态,提高重渲染的性能。
-
在复杂度比较高的场景下,可以考虑用 Mobx/valtio 来管理状态,不管在性能还是社区生态方面都非常出色。
-
在复杂度很高的场景下,使用 Redux/zustand 提高状态的可预测性,约束性的写法也方便后期的维护。

补充一下,业务组件如果要抽象到业务组件库,同样也应该将共享的状态,通过props形式传递到业务组件状态中。

一、zustand
(1)基本使用和优缺点
特点:
store 存储在 React 外部。
优点:
- 支持中间件
- 支持细粒度性能优化
- 有不错的生态中间件支持

缺点:
- 官方缺少derived/computed 状态支持,社区有提供解决方案
(2)原理简单实现
实现的核心函数:
- createStore(状态存储和订阅等)
- useStore(渲染更新机制)
- create(封装createStore和useStore逻辑,返回hook给用户使用)
create参数设计成一个函数,这个函数接收 set、get 等函作为参数,那就自然支持了中间件。
scss
const createStore = (createState) => {
let state;
const listeners = new Set();
...
state = createState(setState, getState, api)
const api = { setState, getState, subscribe, destroy }
return api
}
export const create = (createState) => {
const api = createStore(createState)
const useBoundStore = (selector) => useStore(api, selector)
Object.assign(useBoundStore, api);
return useBoundStore
}
function useStore(api, selector) {
const [,forceRender ] = useState(0);
useEffect(() => {
api.subscribe((state, prevState) => {
const newObj = selector(state);
const oldobj = selector(prevState);
if(newObj !== oldobj) {
forceRender(Math.random());
}
})
}, []);
return selector(api.getState());
}
// 举例createState => createBearState
const createBearState = (set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
updateBears: (newBears) => set({ bears: newBears }),
})
const useBearStore = create(createBearState)
通过selector精确区分组件使用的是store的哪个属性,从而控制细粒度更新(不像context那样的粗粒度)
scss
// 方式1. 使用useState订阅更新
function useStore(api, selector) {
const [,forceRender ] = useState(0);
useEffect(() => {
api.subscribe((state, prevState) => {
const newObj = selector(state);
const oldobj = selector(prevState);
if(newObj !== oldobj) {
forceRender(Math.random());
}
})
}, []);
return selector(api.getState());
}
// 方式2. 使用useSyncExternalStore订阅更新
function useStore(api, selector) {
function getState() {
return selector(api.getState());
}
return useSyncExternalStore(api.subscribe, getState)
}
二、Recoil和Jotai
tutorial.jotai.org/quick-start...
(一)基础用法

支持异步:
tutorial.jotai.org/quick-start...

(二)特点
jotai的语法相比于recoil(Facebook官方推出)更加简洁。
特点:jotai 是 Context 和订阅机制的结合,是面向 React 的一种全局状态管理库。
优点:
- 使用起来十分简单。
- 支持细粒度性能优化。如果你的需求是一个没有额外重复渲染的 Context,那 jotai 是个不错的选择。
- 支持derived/computed 状态。
- 生态系统较好。

缺点:
- 不支持中间件
Zustand 和 Jotai 之间有两个主要不同:
-
Zustand 是单一 store,Jotai 由原子 atom 组合而成;
-
Zustand 的 store 存储在 React 外部,Jotai 的 store 存储在 React 内部。
三、hox
简单易用,跟自定义hooks一模一样。
定位:只用于状态共享,而不是数据操作和状态管理。
优点:
-
支持细粒度性能优化 hox.js.org/zh/guide/pe...
-
较为简单。
缺点:
-
不支持derived/computed 状态
-
不支持中间件功能。
-
缺少生态支持
四、Redux和React-Redux

五、Mobx和Valtio
响应式的,目前项目中不推荐使用。