| 官网 | npm周下载量 | Github star | TS | 特点 | Gziped size | |
|---|---|---|---|---|---|---|
| Jotai | jotai.org/ | 88,756 | 7.7k | 支持 | 小巧、简洁且高性能 | 约3kb |
Jotai是一个原始且灵活的React状态管理库。
-
原始:提供了Hooks方式的Api,使用方式类似于
useState,useReducer
-
灵活:可以组合多个
Atom来创建新的Atom,并且支持异步
-
高性能:更新对应的
Atom只会重新渲染订阅了这个Atom的组件,并不会像Context那样导致整个父组件重新渲染,所以可以做到精确渲染
定义 Atom
atom: 原子的意思。一个Atom代表一个状态,使用atom函数创建一个Atom,需要传入一个参数作为初始值。
import { atom } from 'jotai';
// 定义后并没有与原子关联的值。只有通过 useAtom 使用后的原子,初始值才会存储在状态中
export const textAtom = atom('hello');
// Ts的使用和 React.useState 的方式相同,基础类型可以不定义类型
const numAtom = atom<number>(0)
const numAtom = atom<number | null>(0)
const arrAtom = atom<string[]>([])
使用 Atom
useAtom 函数接受一个参数,参数值为 一个 Atom
返回值是一个数组
数组第一个值是 Atom 存储的值,第二个值是更新 Atom 值的函数
import { useAtom } from 'jotai';
// 类似 React.useState 的用法
// text 读取 textAtom 的值,setText更改值并通知订阅了 textAtom 的组件更新
const [text, setText] = useAtom(textAtom);
创建派生原子,有三种模式
定义或者派生使用时,atom()需要放在函数外,否则会造成死循环。
建议维护一份ts文件单独存放定义的原子
-
Read-only atom
// 只读的 atom(Read-only atom)
const textLenAtom = atom((get) => get(textAtom).length);
// 只读,没有第二个参数
const [len] = useAtom(textLenAtom);
-
Write-only atom
// 只写的 atom
const writeOnlyAtom = atom(
null, // 约定为第一个参数传递 `null`
(get, set, update) => {
// `update` 是我们收到的用于更新这个原子的任何单个值
set(textAtom, `${get(textAtom)} ${update}`);
},
);
// 只写的 atom,第一个参数为 null 不可用
const [, setWrite] = useAtom(writeOnlyAtom);
const handleWrite = () => {
setWrite('world');
};
-
Read-Write atom
// 3. 可读可写的 atom
const readWriteAtom = atom(
(get) => `${get(textAtom)}~`,
(get, set, update: { text: string }) => {
// `update` 是我们收到的用于更新这个原子的任何单个值
set(textAtom, `${get(textAtom)} ${update.text}`);
},
);
const [rw, setRw] = useAtom(readWriteAtom);
const handleReadWriteAtom = () => {
setRw({ text: 'world' });
console.log(rw); // hello world~
};
Provider
Provider 是为一个组件子树提供状态。多个 Provider 可以用于多个子树,甚至可以嵌套。这就像 React Context 一样工作。
在不提供Provider的情况下,会使用默认状态,我们可以不提供他来包裹使用Atom的组件。
<Provider
initialValues={[
[textAtom, 'initval'], // 给 textAtom 原子提供初始值
]}
>
<Input />
<CharCount />
<Uppercase />
</Provider>
使用 Provider 带来的效果
1. 为每个组件树提供不同的状态
2. 包含了一些调试信息
3. 接受原子的初始值initialValues
onMount
创建后的原子可以有一个可选的属性onMount。onMount是一个函数,它接受一个setAtom函数,并可以返回onUnmount函数:一个卸载的函数(类似于useEffect的使用方法)。
onMount当原子首次在提供程序中使用时调用该函数,不再使用时会触发onUnmount卸载函数。
// 顺带着使用派生用法模拟下 reducer
const derivedAtom = atom(
(get) => get(countAtom),
(get, set, action: { type: 'init' | 'inc' | 'dec' }) => {
if (action.type === 'init') {
set(countAtom, 8);
} else if (action.type === 'inc') {
set(countAtom, (c) => c + 1);
} else if (action.type === 'dec') {
set(countAtom, (c) => c - 1);
}
},
);
const [count2, setCount2] = useAtom(derivedAtom);
derivedAtom.onMount = (setAtom) => {
setAtom({ type: 'init' })
}
Utils
内置了很多工具方法,可以根据需要选择使用。
// 以持久化存储的工具方法举例,更多方法详见上方文档
import { atomWithStorage, RESET } from 'jotai/utils';
// atomWithStorage()第一个参数是storage的key值,第二个参数是默认值
const textAtom = atomWithStorage('AtomWithStorageKey', 'hello');
const [text, setText] = useAtom(textAtom);
// RESET可以清楚该storage
setText(RESET)
第三方集成
Jotai内部对多个状态库进行了继承,可根据需要安装对应的包,来配合Jotai使用。
调试工具
Jotai官方提供了两种Debug方式:
- 用Redux DevTools去查看特定
atom的状态,只需要将atom和label传进jotai/devtools中的useAtomDevtoolsHooks。 - 用React Dev Tools去查看Jotai的Provider,全部
atom的状态都存放在DebugState中,但需要额外设定atom的debugLabel作为key,否则会显示为<no debugLabel>。
// 1. Redux DevTools 调试
import { useAtomDevtools } from 'jotai/devtools'
useAtomDevtools(countAtom, 'aaa');
// React DevTools 调试
countAtom.debugLabel = '第一个count';
使用感受
几个月使用下来感觉还是很不错的,非常方便,很多原本使用useState的现在会用useAtom代替,当然亦不可滥用,过犹不及,最好还是用于那些真正有全局使用场景的需求下,或者组件嵌套层级多,不想一层层传递的情况。 但毕竟不是useState,如果在自己的组件中使用,组件卸载时需要注意恢复默认值。避免再次进入时状态混乱。
所以最好还是合理使用useAtom。