简介
Jotai 是一个轻量级的状态管理库,虽然它可以用来做全局状态管理,但我主要将其作为 React 原生 useState 的替代方案。Jotai 采用原子化 (atomic) 的状态管理方式,灵感来源于 Recoil,但实现更加简洁。
为什么选择 Jotai
相比 React 的 useState,Jotai 有以下显著优势:
- 类似 Vue 的计算属性 - 轻松创建派生状态
- 异步更新 - 简化异步数据流管理
- 深层次的对象更新 - 结合 Immer 提供更简洁的 API
- 最小化重新渲染 - 原子化状态使组件只订阅它们需要的状态,减少不必要的重渲染
- 无需 Context 共享状态 - 避免了 Context 的提供者嵌套地狱
- TypeScript 友好 - 提供完善的类型推导,减少类型定义工作
- 体积小巧 - 核心包仅约3KB (min+gzip),按需引入扩展功能
安装
bash
# 基本安装
yarn add jotai
# 如需 immer 集成支持
yarn add immer jotai-immer
基本用法示例
1. 计算属性(Computed Values)
类似于 Vue 的 computed 属性,Jotai 让你可以基于其他状态创建派生状态:
tsx
import {atom, useAtom} from 'jotai';
import {Button, Text, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {ScaledSheet} from 'react-native-size-matters/extend';
// 创建基础原子状态
const countAtom = atom(0);
// 创建派生状态 - 会自动响应 countAtom 的变化
const doubledCountAtom = atom(get => get(countAtom) * 2);
const ComputedExample = () => {
const [count, setCount] = useAtom(countAtom);
const [doubledCount] = useAtom(doubledCountAtom); // 只读,会随 count 自动更新
return (
<SafeAreaView style={styles.container} edges={['top']}>
<View style={styles.content}>
<Text>计数: {count}</Text>
<Text>双倍计数: {doubledCount}</Text>
<Button title="增加" onPress={() => setCount(c => c + 1)} />
</View>
</SafeAreaView>
);
};
与 useState 相比,这种方式让派生状态变得非常简单,无需使用 useMemo 或在 useEffect 中手动同步状态。
2. 异步状态处理
Jotai 原生支持异步 atom,搭配 React Suspense 可以优雅地处理加载状态:
tsx
import {atom, useAtom} from 'jotai';
import {Button, Text, View} from 'react-native';
import {Suspense} from 'react';
// 基础状态
const countAtom = atom(0);
// 异步派生状态
const asyncAtom = atom(async get => {
// 模拟API请求
return new Promise<number>(resolve => {
setTimeout(() => {
resolve(get(countAtom) * 2);
}, 1000);
});
});
// 异步组件会被Suspense捕获并展示加载状态
function AsyncComponent() {
const [asyncValue] = useAtom(asyncAtom);
return <Text>异步计算结果: {asyncValue}</Text>;
}
const AsyncExample = () => {
const [count, setCount] = useAtom(countAtom);
return (
<View style={styles.content}>
<Text>当前计数: {count}</Text>
<Suspense fallback={<Text>加载中...</Text>}>
<AsyncComponent />
</Suspense>
<Button title="增加" onPress={() => setCount(c => c + 1)} />
</View>
);
};
这种模式大大简化了异步数据处理,告别了传统的 isLoading
状态标志和复杂的加载控制逻辑。
3. 深层嵌套对象的简化更新
结合 jotai-immer,Jotai 可以极大简化复杂嵌套对象的更新:
tsx
import {useAtom} from 'jotai';
import {atomWithImmer} from 'jotai-immer';
import {Button, Text, View} from 'react-native';
// 使用 atomWithImmer 创建可变的 atom
const userAtom = atomWithImmer({
name: 'John',
profile: {
address: {
city: 'Shanghai',
street: 'Nanjing Road',
zipCode: '200000'
},
preferences: {
theme: 'light',
notifications: true
}
},
});
const DeepUpdateExample = () => {
const [user, setUser] = useAtom(userAtom);
return (
<View style={styles.content}>
<Text>{JSON.stringify(user, null, 2)}</Text>
<Button
title="更新城市和主题"
onPress={() => {
// 使用类似 Immer 的 API 直接修改嵌套属性
setUser(draft => {
draft.name = 'Lai';
draft.profile.address.city = 'Beijing';
draft.profile.preferences.theme = 'dark';
});
// 对比传统 useState 的繁琐写法:
// setUser(prevState => ({
// ...prevState,
// name: 'Lai',
// profile: {
// ...prevState.profile,
// address: {
// ...prevState.profile.address,
// city: 'Beijing',
// },
// preferences: {
// ...prevState.profile.preferences,
// theme: 'dark'
// }
// },
// }));
}}
/>
</View>
);
};
在组件间共享状态
Jotai 还允许你轻松在不同组件间共享状态,无需使用 Context API:
tsx
// atoms.ts - 集中定义共享状态
import {atom} from 'jotai';
// 在模块级别定义共享的atom
export const globalBooleanAtom = atom(false);
export const themeAtom = atom('light');
export const userSessionAtom = atom(null);
tsx
// 在任意组件中使用
import {useAtom} from 'jotai';
import {globalBooleanAtom, themeAtom} from './atoms';
const ComponentA = () => {
const [isEnabled, setIsEnabled] = useAtom(globalBooleanAtom);
return (
<Switch
value={isEnabled}
onValueChange={setIsEnabled}
/>
);
};
const ComponentB = () => {
// 在另一个组件中使用相同的状态
const [isEnabled] = useAtom(globalBooleanAtom);
const [theme, setTheme] = useAtom(themeAtom);
return (
<View>
<Text>功能已{isEnabled ? '启用' : '禁用'}</Text>
<Text>当前主题: {theme}</Text>
<Button
title="切换主题"
onPress={() => setTheme(t => t === 'light' ? 'dark' : 'light')}
/>
</View>
);
};
总结
相比 React 的内置状态管理,Jotai 提供了更强大、简洁的 API:
- 派生状态让数据间的依赖关系更加清晰
- 异步处理简化了数据加载和同步
- 深层对象更新告别了繁琐的展开操作
- 状态共享无需复杂的 Context 配置
- 精确重渲染减少应用性能浪费
- 模块化设计便于代码组织和维护
- 插件生态系统提供各种扩展功能
相关资源
Tips
本专栏的代码已开源,后续随着专栏会不断更新[github.com/ace0109/rea...)