React 状态管理:Jotai 快速上手指南
🤔 为什么需要 Jotai?
在 React 应用开发中,我们经常会遇到以下状态管理难题:
- 全局状态管理过于复杂,需要大量的样板代码
- 组件间状态共享需要多层嵌套的 Context
- 状态更新可能导致不必要的组件重新渲染
- 原子状态与派生状态的管理不够灵活
而 Jotai 就是为了解决这些问题而生的!它是一个基于原子(Atoms)的轻量级 React 状态管理库,具有以下特点:
- ⚛️ 原子化:将状态拆分为独立的原子单元,便于管理和复用
- 🎯 灵活:支持原子状态和派生状态的组合
- ⚡ 高性能:基于 React 的细粒度更新机制,只更新依赖的组件
- 🔄 异步支持:轻松处理异步状态
- 📦 扩展能力强:支持持久化、DevTools、React Native 等
- 🔧 易于集成:可以与其他状态管理库(如 Zustand、Redux)无缝集成
💡 Jotai 核心概念
在 Jotai 中,有两个核心概念:
- Atom:原子状态单元,可以是任何类型的值
- useAtom:用于在组件中使用原子状态的 Hook
Jotai 的设计灵感来自于 Recoil,但相比之下,Jotai 更加轻量级且易于使用。
🚀 Jotai 基础实现
1. 安装 Jotai
npm install jotai
# 或
yarn add jotai
# 或
pnpm add jotai
2. 创建基本原子
使用 atom 函数创建一个原子状态:
import { atom } from 'jotai';
// 创建一个简单的计数器原子
const countAtom = atom(0);
// 创建一个字符串原子
const nameAtom = atom('Jotai');
// 创建一个对象原子
const userAtom = atom({
id: 1,
name: 'John Doe',
email: 'john@example.com'
});
3. 在组件中使用原子
使用 useAtom Hook 在组件中访问和更新原子状态:
import React from 'react';
import { useAtom } from 'jotai';
import { countAtom, nameAtom } from './atoms';
const CounterComponent = () => {
// 解构出状态和更新函数
const [count, setCount] = useAtom(countAtom);
const [name, setName] = useAtom(nameAtom);
return (
<div>
<h2>欢迎使用 {name}!</h2>
<p>当前计数: {count}</p>
<div>
setCount(count + 1)}>增加
setCount(count - 1)}>减少
setCount(0)}>重置
</div>
<div>
修改名称:
setName(e.target.value)}
/>
</div>
</div>
);
};
export default CounterComponent;
🎯 Jotai 进阶用法
1. 派生原子(Derived Atoms)
派生原子是基于其他原子计算得出的状态,可以使用函数作为参数创建:
import { atom } from 'jotai';
// 基础原子
const countAtom = atom(0);
// 派生原子:基于 countAtom 计算
const doubledCountAtom = atom((get) => get(countAtom) * 2);
// 派生原子:将多个原子组合
const firstNameAtom = atom('John');
const lastNameAtom = atom('Doe');
const fullNameAtom = atom((get) => `${get(firstNameAtom)} ${get(lastNameAtom)}`);
// 使用派生原子
const [doubledCount] = useAtom(doubledCountAtom);
const [fullName] = useAtom(fullNameAtom);
2. 异步原子(Async Atoms)
Jotai 支持异步原子,可以用于获取 API 数据:
import { atom } from 'jotai';
// 异步原子:获取用户列表
const usersAtom = atom(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
return response.json();
});
// 在组件中使用
const UsersList = () => {
const [users, setUsers] = useAtom(usersAtom);
if (users === undefined) {
return <div>加载中...</div>;
}
return (
<ul>
{users.map((user) => (
<li>{user.name}</li>
))}
</ul>
);
};
3. 可写的派生原子
默认情况下,派生原子是只读的,但可以通过提供一个更新函数使其可写:
import { atom } from 'jotai';
// 基础原子
const firstNameAtom = atom('John');
const lastNameAtom = atom('Doe');
// 可写的派生原子
const fullNameAtom = atom(
// getter:计算全名
(get) => `${get(firstNameAtom)} ${get(lastNameAtom)}`,
// setter:解析全名并更新基础原子
(get, set, newValue) => {
const [firstName, lastName] = newValue.split(' ');
set(firstNameAtom, firstName || '');
set(lastNameAtom, lastName || '');
}
);
// 使用
const [fullName, setFullName] = useAtom(fullNameAtom);
setFullName('Jane Smith'); // 会同时更新 firstNameAtom 和 lastNameAtom
4. 原子的作用域(Scope)
Jotai 支持原子的作用域,可以在不同的组件树中使用不同的原子值:
import React from 'react';
import { atom, useAtom, createScope, Provider } from 'jotai';
// 创建一个全局原子
const countAtom = atom(0);
// 创建一个作用域
const counterScope = createScope();
const Counter = () => {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<p>计数: {count}</p>
setCount(count + 1)}>增加
</div>
);
};
const App = () => {
return (
<div>
<h2>全局计数</h2>
<h2>作用域计数</h2>
</div>
);
};
5. 持久化原子
使用 jotai/utils 中的 atomWithStorage 函数可以创建持久化原子:
import { atomWithStorage } from 'jotai/utils';
// 创建一个持久化的计数器原子
const countAtom = atomWithStorage('count', 0);
// 创建一个持久化的用户原子
const userAtom = atomWithStorage('user', {
id: 1,
name: 'John Doe'
});
6. 与其他库集成
Jotai 可以与其他状态管理库无缝集成:
与 Zustand 集成
import { atom } from 'jotai';
import { useCounterStore } from './zustandStore';
// 创建一个基于 Zustand store 的原子
const countFromZustandAtom = atom((get) => {
// 使用自定义 hook 获取 Zustand store 的状态
const { count } = useCounterStore();
return count;
});
与 Redux 集成
import { atom } from 'jotai';
import { useSelector } from 'react-redux';
// 创建一个基于 Redux store 的原子
const countFromReduxAtom = atom((get) => {
return useSelector((state) => state.counter.count);
});
📝 Jotai 最佳实践
- 原子化拆分:将状态拆分为最小的原子单元,提高复用性和可维护性
- 合理使用派生原子:使用派生原子处理计算逻辑,保持基础原子的简洁
- 异步原子的错误处理:在异步原子中添加错误处理,提高应用的稳定性
- 性能优化:使用
useAtomValue和useSetAtom替代useAtom,减少不必要的重新渲染 - 类型安全:使用 TypeScript 为原子添加类型定义,提高代码质量
- 避免过度使用:对于简单的组件内状态,仍然使用
useState,只在需要跨组件共享时使用 Jotai
🎯 Jotai 适用场景
Jotai 适用于以下场景:
- 需要细粒度状态管理的应用
- 状态之间存在复杂依赖关系的项目
- 希望减少不必要的组件重新渲染的应用
- 需要灵活组合状态的项目
- 希望使用原子化状态管理的项目
🔧 Jotai 与其他状态管理库的比较
| 特性 | Jotai | Zustand | Redux |
|---|---|---|---|
| 大小 | ~2KB | ~1KB | ~2KB |
| 学习曲线 | 中 | 低 | 高 |
| 原子化 | 是 | 否 | 否 |
| 派生状态 | 内置 | 需要手动实现 | 需要中间件 |
| 异步支持 | 内置 | 内置 | 需要中间件 |
| 作用域支持 | 是 | 否 | 否 |
| 持久化支持 | 是 | 是 | 需要中间件 |
🚀 总结
Jotai 是一个基于原子的轻量级 React 状态管理库,它提供了灵活的状态管理方式和高性能的状态更新机制。通过将状态拆分为独立的原子单元,Jotai 使得状态管理更加直观和易于维护。
无论是中小型应用还是大型项目,Jotai 都能很好地满足状态管理的需求。如果你正在寻找一个替代传统状态管理库的方案,或者想要尝试原子化的状态管理方式,那么 Jotai 绝对值得一试!
下一篇文章,我们将介绍 Redux Toolkit,这是 Redux 官方推荐的现代化 Redux 开发方式,敬请期待!✨