React 状态管理:Jotai 快速上手指南

58 阅读5分钟

React 状态管理:Jotai 快速上手指南

🤔 为什么需要 Jotai?

在 React 应用开发中,我们经常会遇到以下状态管理难题:

  • 全局状态管理过于复杂,需要大量的样板代码
  • 组件间状态共享需要多层嵌套的 Context
  • 状态更新可能导致不必要的组件重新渲染
  • 原子状态与派生状态的管理不够灵活

Jotai 就是为了解决这些问题而生的!它是一个基于原子(Atoms)的轻量级 React 状态管理库,具有以下特点:

  • ⚛️ 原子化:将状态拆分为独立的原子单元,便于管理和复用
  • 🎯 灵活:支持原子状态和派生状态的组合
  • 高性能:基于 React 的细粒度更新机制,只更新依赖的组件
  • 🔄 异步支持:轻松处理异步状态
  • 📦 扩展能力强:支持持久化、DevTools、React Native 等
  • 🔧 易于集成:可以与其他状态管理库(如 Zustand、Redux)无缝集成

💡 Jotai 核心概念

在 Jotai 中,有两个核心概念:

  1. Atom:原子状态单元,可以是任何类型的值
  2. 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 最佳实践

  1. 原子化拆分:将状态拆分为最小的原子单元,提高复用性和可维护性
  2. 合理使用派生原子:使用派生原子处理计算逻辑,保持基础原子的简洁
  3. 异步原子的错误处理:在异步原子中添加错误处理,提高应用的稳定性
  4. 性能优化:使用 useAtomValueuseSetAtom 替代 useAtom,减少不必要的重新渲染
  5. 类型安全:使用 TypeScript 为原子添加类型定义,提高代码质量
  6. 避免过度使用:对于简单的组件内状态,仍然使用 useState,只在需要跨组件共享时使用 Jotai

🎯 Jotai 适用场景

Jotai 适用于以下场景:

  • 需要细粒度状态管理的应用
  • 状态之间存在复杂依赖关系的项目
  • 希望减少不必要的组件重新渲染的应用
  • 需要灵活组合状态的项目
  • 希望使用原子化状态管理的项目

🔧 Jotai 与其他状态管理库的比较

特性JotaiZustandRedux
大小~2KB~1KB~2KB
学习曲线
原子化
派生状态内置需要手动实现需要中间件
异步支持内置内置需要中间件
作用域支持
持久化支持需要中间件

🚀 总结

Jotai 是一个基于原子的轻量级 React 状态管理库,它提供了灵活的状态管理方式和高性能的状态更新机制。通过将状态拆分为独立的原子单元,Jotai 使得状态管理更加直观和易于维护。

无论是中小型应用还是大型项目,Jotai 都能很好地满足状态管理的需求。如果你正在寻找一个替代传统状态管理库的方案,或者想要尝试原子化的状态管理方式,那么 Jotai 绝对值得一试!

下一篇文章,我们将介绍 Redux Toolkit,这是 Redux 官方推荐的现代化 Redux 开发方式,敬请期待!✨