初步了解轻量高效的React状态库Jotai

初步了解轻量高效的 React 状态库 Jotai

Jotai 是什么

Jotai 是状态管理库,原子化思想,提供一个最基础的原子,通过组合原子来构建状态,并且基于原子依懒性进行优化渲染,避免了 React 额外的渲染。Atom 在 Jotai 中是状态单位(原子),可以更新也可以被组件订阅(使用useAtom),当 Atom 更新了,那么订阅这个 Atom 的组件便会重新渲染。

  • 创建原子过程就和使用 useState Hook 一样简单方便,并且全局可用的。const nameAtom = atom('chenjiang')
  • 使用灵活:可以基于这个或者一些原子,从而衍生出更多状态。

Jotai 适用场景

  • 中小型项目:Jotai 设计的目标就是轻量且易用,适合中小型项目,不需要复杂的状态管理。

  • 需要局部状态管理:Jotai 采用原子状态概念,意味着可以将状态拆解为独立的、可组合的原子单元。不需要全局状态管理库的复杂性。

  • 组件间的状态传递:Jotai 可以让多个组件共享相同的原子状态,并且支持同步更新和跨组件传递状态。可以减少 Context 或者 Props 传递过程的繁琐及产生不必要的渲染。

  • 高效的异步操作:Jotai 支持异步操作,使用 atom 配合异步函数,可以优雅的管理数据状态。

  • 替代 Context 或 Redux:Jotai 是一个更加简洁的状态管理工具,可以替代复杂的 Context 和 Redux,尤其当项目不需要全局状态或者深层的状态管理时。

  • 开发者希望拥有更细粒度控制场景:Jotai 的原子状态机制允许你精确的控制每个状态更新和影响范围。相比传统的 Redux,没有过多的样板代码,提供了更高的灵活性。

  • 需要状态持久化:Jotai 提供 API 可以与localStoragesessionStorage配合,支持状态持久化到客户端。
    s

Jotai 设计理念

  • 原子化:将状态拆分为小的、独立的单元,Jotai 是状态变的更加准确,从而提高了性能和可维护性。每个组件只会重新渲染它所依赖的原子,而不是整个应用。

  • React 原生集成:不需要引入复杂的方法,直接能够与 React 现有的功能集成。学习曲线低,避免了传统的状态管理库的复杂配置和样板代码,更容易上手。

  • 细粒度的状态管理:状态细分为多个小的原子,每个原子代表一个特定的、独立的状态单元,开发者可以灵活的组合和管理这些原子。通过这种状态管理,Jotai 能够更加精确的控制,每个原子的更新只会影响那些依赖它的组件,避免了不必要的渲染,从而提高应用性能。

  • 更好的异步操作:Jotai 支持异步原子的创建,可以将异步操作集成到原子中。不需要再为异步操作编写额外的逻辑或者使用特殊的中间件(例如:Redux Thunk),只需要将异步操作封装为原子即可。

初步体验原子状态

和 useState 类似,useAtom 会返回一个最新的原子状态和修改原子状态的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { atom, useAtom } from "jotai";
import "./App.css";

const nameAtom = atom("chenjiang"); // 创建一个原子

function App() {
const [name, setName] = useAtom(nameAtom); // 使用原子或者说App组件订阅了这个原子

return (
<>
<button
onClick={() => {
setName(name + "123"); // 更新原子的值
}}
>
修改name
</button>
<h1>{name}</h1>
</>
);
}
export default App;

原子可组合性(基于原子衍生出更多状态)

某个原子依赖另外一个原子,当依赖的原子更新了,那么当前的原子也随之更新。
例如:name 大写这个 atom 它本身依赖 name,当最基础的 name 发生了变化,name 大写也会更新,订阅此原子的组件也重新渲染。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const nameAtom = atom("chenjiang");

const nameUppercaseAtom = atom((get) => get(nameAtom).toUpperCase());

const Uppercase = () => {
const [uppercaseName] = useAtom(nameUppercaseAtom);
return <h1>{uppercaseName}</h1>;
};

function App() {
const [name, setName] = useAtom(nameAtom);

return (
<>
<button
onClick={() => {
setName(name + "666");
}}
>
修改name
</button>
<Uppercase />
</>
);
}

状态持久化

一般来说页面刷新后,所有的状态都丢失,都恢复成初始值。Jotai 提供了一个工具方法atomWithStorage ,保留原子状态到 localStorage(默认)。

localstorage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { useAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";

const nameAtom = atomWithStorage("name", "chenjiang");

function App() {
const [name, setName] = useAtom(nameAtom);

return (
<>
<button
onClick={() => {
setName(name + "666");
}}
>
修改name
</button>
<h1>{name}</h1>
</>
);
}

自定义存储

1
2
3
4
5
6
7
8
9
const sessionStorageAtom = atomWithStorage(
"sessionKey", // 存储键名
"defaultValue", // 默认值
{
getItem: (key) => {}, // 自定义的 get 方法
setItem: (key, value) => {}, // 自定义的 set 方法
removeItem: (key) => {}, // 自定义的 remove 方法
}
);

sessionStorage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { useAtom } from "jotai";
import { atomWithStorage, createJSONStorage } from "jotai/utils";

const storage = createJSONStorage(() => sessionStorage);
const nameAtom = atomWithStorage("name", "chenjiang", storage);

function App() {
const [name, setName] = useAtom(nameAtom);

return (
<>
<button
onClick={() => {
setName(name + "666");
}}
>
修改name
</button>
<h1>{name}</h1>
</>
);
}

可复原的原子状态

通过atomWithReset定义可还原原子,再通过useResetAtomhook 创建一个可还原的方法。
类似表单的重置功能,对原子进行一系列更新之后复原,回到最初始状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { useAtom } from "jotai";
import { atomWithReset, useResetAtom } from "jotai/utils";

const nameAtom = atomWithReset("chenjiang");

function App() {
const [name, setName] = useAtom(nameAtom); // 使用原子
const resetName = useResetAtom(nameAtom); // 重置原子

return (
<>
<button
onClick={() => {
setName(name + "666");
}}
>
修改name
</button>
<button onClick={resetName}>复原</button>
<h1>{name}</h1>
</>
);
}