Skip to content

Recoil原子状态

概述

Recoil是Facebook开发的React状态管理库,采用原子化状态管理理念。它将状态拆分为独立的原子(atoms),通过自底向上的方式构建复杂的状态图,提供了优秀的性能和并发模式支持。

为什么选择Recoil

Recoil的优势

  1. 原子化设计:状态被拆分为最小的可复用单元
  2. 依赖追踪:自动追踪状态依赖关系
  3. 并发模式:完美支持React 18+的并发特性
  4. 时间旅行:内置调试和时间旅行功能
  5. 异步支持:原生支持异步状态和Suspense
  6. 细粒度更新:只有依赖的组件才会重渲染
  7. 开发工具:强大的调试和可视化工具

核心概念

jsx
import { atom, selector, useRecoilState, useRecoilValue } from 'recoil';

// Atom - 状态的最小单元
const counterAtom = atom({
  key: 'counter', // 全局唯一key
  default: 0      // 默认值
});

// Selector - 派生状态
const doubledCounterSelector = selector({
  key: 'doubledCounter',
  get: ({get}) => {
    const count = get(counterAtom);
    return count * 2;
  }
});

// 在组件中使用
function Counter() {
  const [count, setCount] = useRecoilState(counterAtom);
  const doubledCount = useRecoilValue(doubledCounterSelector);

  return (
    <div>
      <p>Count: {count}</p>
      <p>Doubled: {doubledCount}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

安装和基础设置

安装

bash
# npm
npm install recoil

# yarn
yarn add recoil

# pnpm
pnpm add recoil

RecoilRoot设置

jsx
import { RecoilRoot } from 'recoil';

function App() {
  return (
    <RecoilRoot>
      <MainApp />
    </RecoilRoot>
  );
}

// 使用initializeState初始化状态
function AppWithInitialState() {
  return (
    <RecoilRoot initializeState={({set}) => {
      set(counterAtom, 10);
      set(userAtom, { name: 'John', email: 'john@example.com' });
    }}>
      <MainApp />
    </RecoilRoot>
  );
}

Atoms详解

基础Atom

jsx
import { atom } from 'recoil';

// 基本类型
const countAtom = atom({
  key: 'count',
  default: 0
});

const nameAtom = atom({
  key: 'name', 
  default: 'John Doe'
});

const activeAtom = atom({
  key: 'active',
  default: false
});

// 对象类型
const userAtom = atom({
  key: 'user',
  default: {
    id: null,
    name: '',
    email: '',
    preferences: {}
  }
});

// 数组类型
const todosAtom = atom({
  key: 'todos',
  default: []
});

// 复杂默认值
const configAtom = atom({
  key: 'config',
  default: {
    theme: 'light',
    language: 'en-US',
    features: {
      darkMode: true,
      notifications: true
    },
    cache: new Map(),
    lastUpdated: new Date().toISOString()
  }
});

Atom Effects

Atom Effects提供了强大的副作用处理能力:

jsx
import { atom } from 'recoil';

// 持久化Effect
const persistEffect = (key) => ({onSet}) => {
  onSet(newValue => {
    if (newValue instanceof DefaultValue) {
      localStorage.removeItem(key);
    } else {
      localStorage.setItem(key, JSON.stringify(newValue));
    }
  });
};

// 同步Effect
const syncEffect = (key) => ({setSelf, onSet}) => {
  // 初始化时从localStorage读取
  const savedValue = localStorage.getItem(key);
  if (savedValue != null) {
    setSelf(JSON.parse(savedValue));
  }

  // 监听变化并保存
  onSet(newValue => {
    if (newValue instanceof DefaultValue) {
      localStorage.removeItem(key);
    } else {
      localStorage.setItem(key, JSON.stringify(newValue));
    }
  });
};

// 使用Effects的Atom
const persistentCountAtom = atom({
  key: 'persistentCount',
  default: 0,
  effects: [
    syncEffect('persistentCount')
  ]
});

// 网络同步Effect
const networkSyncEffect = (endpoint) => ({setSelf, onSet, trigger}) => {
  // 只在用户操作时触发
  if (trigger === 'get') {
    // 从服务器获取初始值
    fetch(endpoint)
      .then(res => res.json())
      .then(data => setSelf(data))
      .catch(err => console.error('Failed to load:', err));
  }

  // 监听变化并同步到服务器
  onSet(newValue => {
    if (!(newValue instanceof DefaultValue)) {
      fetch(endpoint, {
        method: 'PUT',
        body: JSON.stringify(newValue),
        headers: { 'Content-Type': 'application/json' }
      }).catch(err => console.error('Failed to sync:', err));
    }
  });
};

const serverSyncedAtom = atom({
  key: 'serverSynced',
  default: null,
  effects: [
    networkSyncEffect('/api/user-preferences')
  ]
});

// 日志Effect
const loggerEffect = (label) => ({onSet}) => {
  onSet(newValue => {
    console.log(`[${label}] State changed:`, newValue);
  });
};

// 验证Effect
const validationEffect = (validator) => ({setSelf, onSet}) => {
  onSet(newValue => {
    if (!(newValue instanceof DefaultValue)) {
      const isValid = validator(newValue);
      if (!isValid) {
        console.warn('Invalid value rejected:', newValue);
        return; // 阻止状态更新
      }
    }
  });
};

const validatedAtom = atom({
  key: 'validated',
  default: '',
  effects: [
    validationEffect(value => typeof value === 'string' && value.length > 0),
    loggerEffect('ValidatedAtom')
  ]
});

Atom Family

Atom Family用于创建参数化的atoms:

jsx
import { atomFamily } from 'recoil';

// 基础Atom Family
const userAtomFamily = atomFamily({
  key: 'user',
  default: (userId) => ({
    id: userId,
    name: '',
    email: '',
    loading: false
  })
});

// 使用
function UserProfile({ userId }) {
  const [user, setUser] = useRecoilState(userAtomFamily(userId));
  
  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
    </div>
  );
}

// 带异步默认值的Atom Family
const userDataFamily = atomFamily({
  key: 'userData',
  default: async (userId) => {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  }
});

// 复杂参数的Atom Family
const itemFamily = atomFamily({
  key: 'item',
  default: ({id, type}) => ({
    id,
    type,
    data: null,
    lastUpdated: null
  })
});

// 使用复杂参数
function ItemComponent() {
  const [item, setItem] = useRecoilState(itemFamily({id: 1, type: 'product'}));
  
  return <div>{item.data?.name}</div>;
}

// 带Effects的Atom Family
const cachedDataFamily = atomFamily({
  key: 'cachedData',
  default: null,
  effects: (param) => [
    ({setSelf, onSet}) => {
      // 从缓存加载
      const cached = localStorage.getItem(`cache-${param}`);
      if (cached) {
        setSelf(JSON.parse(cached));
      }

      // 保存到缓存
      onSet(newValue => {
        if (newValue instanceof DefaultValue) {
          localStorage.removeItem(`cache-${param}`);
        } else {
          localStorage.setItem(`cache-${param}`, JSON.stringify(newValue));
        }
      });
    }
  ]
});

使用Atoms

基础Hooks

jsx
import { 
  useRecoilState, 
  useRecoilValue, 
  useSetRecoilState, 
  useResetRecoilState 
} from 'recoil';

function TodoApp() {
  // 读写状态
  const [todos, setTodos] = useRecoilState(todosAtom);
  
  // 只读状态
  const todoCount = useRecoilValue(todoCountSelector);
  
  // 只写状态
  const setFilter = useSetRecoilState(filterAtom);
  
  // 重置状态
  const resetTodos = useResetRecoilState(todosAtom);

  const addTodo = (text) => {
    setTodos(prev => [
      ...prev,
      { id: Date.now(), text, completed: false }
    ]);
  };

  return (
    <div>
      <p>Total todos: {todoCount}</p>
      <button onClick={() => addTodo('New todo')}>Add Todo</button>
      <button onClick={resetTodos}>Clear All</button>
      
      {todos.map(todo => (
        <div key={todo.id}>
          <span>{todo.text}</span>
          <input
            type="checkbox"
            checked={todo.completed}
            onChange={(e) => {
              setTodos(prev => prev.map(t => 
                t.id === todo.id 
                  ? { ...t, completed: e.target.checked }
                  : t
              ));
            }}
          />
        </div>
      ))}
    </div>
  );
}

回调Hooks

jsx
import { useRecoilCallback } from 'recoil';

function TodoManager() {
  // 批量操作
  const batchUpdateTodos = useRecoilCallback(({snapshot, set}) => 
    async (updates) => {
      const currentTodos = await snapshot.getPromise(todosAtom);
      
      const newTodos = currentTodos.map(todo => {
        const update = updates.find(u => u.id === todo.id);
        return update ? { ...todo, ...update.changes } : todo;
      });
      
      set(todosAtom, newTodos);
    }
  );

  // 异步操作
  const syncTodosToServer = useRecoilCallback(({snapshot}) =>
    async () => {
      const todos = await snapshot.getPromise(todosAtom);
      
      try {
        await fetch('/api/todos', {
          method: 'POST',
          body: JSON.stringify(todos)
        });
      } catch (error) {
        console.error('Sync failed:', error);
      }
    }
  );

  // 获取快照
  const logCurrentState = useRecoilCallback(({snapshot}) =>
    async () => {
      const todos = await snapshot.getPromise(todosAtom);
      const filter = await snapshot.getPromise(filterAtom);
      
      console.log('Current state:', { todos, filter });
    }
  );

  return (
    <div>
      <button onClick={() => batchUpdateTodos([
        { id: 1, changes: { completed: true } },
        { id: 2, changes: { text: 'Updated text' } }
      ])}>
        Batch Update
      </button>
      
      <button onClick={syncTodosToServer}>
        Sync to Server
      </button>
      
      <button onClick={logCurrentState}>
        Log State
      </button>
    </div>
  );
}

实战案例

案例1:用户管理系统

jsx
import { atom, selector, atomFamily, useRecoilState, useRecoilValue } from 'recoil';

// 用户列表atom
const usersAtom = atom({
  key: 'users',
  default: []
});

// 当前用户ID atom
const currentUserIdAtom = atom({
  key: 'currentUserId',
  default: null
});

// 用户搜索查询atom
const userSearchQueryAtom = atom({
  key: 'userSearchQuery',
  default: ''
});

// 用户排序atom
const userSortAtom = atom({
  key: 'userSort',
  default: { field: 'name', direction: 'asc' }
});

// 单个用户atom family
const userAtomFamily = atomFamily({
  key: 'user',
  default: (userId) => {
    // 从用户列表中查找
    return selector({
      key: `userFromList-${userId}`,
      get: ({get}) => {
        const users = get(usersAtom);
        return users.find(user => user.id === userId) || null;
      }
    });
  }
});

// 过滤后的用户列表selector
const filteredUsersSelector = selector({
  key: 'filteredUsers',
  get: ({get}) => {
    const users = get(usersAtom);
    const searchQuery = get(userSearchQueryAtom);
    const sort = get(userSortAtom);

    // 搜索过滤
    let filtered = users.filter(user =>
      user.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
      user.email.toLowerCase().includes(searchQuery.toLowerCase())
    );

    // 排序
    filtered.sort((a, b) => {
      const aValue = a[sort.field];
      const bValue = b[sort.field];
      
      if (aValue < bValue) return sort.direction === 'asc' ? -1 : 1;
      if (aValue > bValue) return sort.direction === 'asc' ? 1 : -1;
      return 0;
    });

    return filtered;
  }
});

// 当前用户selector
const currentUserSelector = selector({
  key: 'currentUser',
  get: ({get}) => {
    const userId = get(currentUserIdAtom);
    if (!userId) return null;
    
    return get(userAtomFamily(userId));
  }
});

// 用户统计selector
const userStatsSelector = selector({
  key: 'userStats',
  get: ({get}) => {
    const users = get(usersAtom);
    
    return {
      total: users.length,
      active: users.filter(u => u.active).length,
      inactive: users.filter(u => !u.active).length,
      admins: users.filter(u => u.role === 'admin').length
    };
  }
});

// 组件
function UserManagement() {
  const [users, setUsers] = useRecoilState(usersAtom);
  const [searchQuery, setSearchQuery] = useRecoilState(userSearchQueryAtom);
  const [sort, setSort] = useRecoilState(userSortAtom);
  const filteredUsers = useRecoilValue(filteredUsersSelector);
  const stats = useRecoilValue(userStatsSelector);

  const addUser = (userData) => {
    const newUser = {
      id: Date.now(),
      ...userData,
      createdAt: new Date().toISOString(),
      active: true
    };
    
    setUsers(prev => [...prev, newUser]);
  };

  const deleteUser = (userId) => {
    setUsers(prev => prev.filter(user => user.id !== userId));
  };

  return (
    <div>
      <div className="user-stats">
        <h2>User Statistics</h2>
        <p>Total: {stats.total}</p>
        <p>Active: {stats.active}</p>
        <p>Inactive: {stats.inactive}</p>
        <p>Admins: {stats.admins}</p>
      </div>

      <div className="user-controls">
        <input
          type="text"
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          placeholder="Search users..."
        />
        
        <select
          value={`${sort.field}-${sort.direction}`}
          onChange={(e) => {
            const [field, direction] = e.target.value.split('-');
            setSort({ field, direction });
          }}
        >
          <option value="name-asc">Name (A-Z)</option>
          <option value="name-desc">Name (Z-A)</option>
          <option value="email-asc">Email (A-Z)</option>
          <option value="createdAt-desc">Newest First</option>
          <option value="createdAt-asc">Oldest First</option>
        </select>
      </div>

      <UserList users={filteredUsers} onDelete={deleteUser} />
      <AddUserForm onAdd={addUser} />
    </div>
  );
}

function UserList({ users, onDelete }) {
  return (
    <div className="user-list">
      {users.map(user => (
        <UserCard key={user.id} userId={user.id} onDelete={onDelete} />
      ))}
    </div>
  );
}

function UserCard({ userId, onDelete }) {
  const user = useRecoilValue(userAtomFamily(userId));
  const [currentUserId, setCurrentUserId] = useRecoilState(currentUserIdAtom);

  if (!user) return null;

  return (
    <div className={`user-card ${currentUserId === userId ? 'selected' : ''}`}>
      <h3>{user.name}</h3>
      <p>{user.email}</p>
      <p>Role: {user.role}</p>
      <p>Status: {user.active ? 'Active' : 'Inactive'}</p>
      
      <div className="user-actions">
        <button onClick={() => setCurrentUserId(userId)}>
          Select
        </button>
        <button onClick={() => onDelete(userId)}>
          Delete
        </button>
      </div>
    </div>
  );
}

function CurrentUserProfile() {
  const currentUser = useRecoilValue(currentUserSelector);

  if (!currentUser) {
    return <div>No user selected</div>;
  }

  return (
    <div className="current-user-profile">
      <h2>Current User Profile</h2>
      <p>Name: {currentUser.name}</p>
      <p>Email: {currentUser.email}</p>
      <p>Role: {currentUser.role}</p>
      <p>Created: {new Date(currentUser.createdAt).toLocaleDateString()}</p>
    </div>
  );
}

案例2:购物车系统

jsx
import { atom, selector, atomFamily, selectorFamily } from 'recoil';

// 产品数据atom family
const productFamily = atomFamily({
  key: 'product',
  default: async (productId) => {
    const response = await fetch(`/api/products/${productId}`);
    return response.json();
  }
});

// 购物车items atom
const cartItemsAtom = atom({
  key: 'cartItems',
  default: [],
  effects: [
    ({setSelf, onSet}) => {
      // 从localStorage加载
      const saved = localStorage.getItem('cartItems');
      if (saved) {
        setSelf(JSON.parse(saved));
      }

      // 保存到localStorage
      onSet(newValue => {
        if (newValue instanceof DefaultValue) {
          localStorage.removeItem('cartItems');
        } else {
          localStorage.setItem('cartItems', JSON.stringify(newValue));
        }
      });
    }
  ]
});

// 折扣代码atom
const discountCodeAtom = atom({
  key: 'discountCode',
  default: ''
});

// 运费选项atom
const shippingOptionAtom = atom({
  key: 'shippingOption',
  default: null
});

// 购物车商品详情selector
const cartItemsWithDetailsSelector = selector({
  key: 'cartItemsWithDetails',
  get: async ({get}) => {
    const items = get(cartItemsAtom);
    
    const itemsWithDetails = await Promise.all(
      items.map(async (item) => {
        const product = await get(productFamily(item.productId));
        return {
          ...item,
          product,
          subtotal: product.price * item.quantity
        };
      })
    );
    
    return itemsWithDetails;
  }
});

// 购物车统计selector
const cartStatsSelector = selector({
  key: 'cartStats',
  get: ({get}) => {
    const items = get(cartItemsWithDetailsSelector);
    
    const subtotal = items.reduce((sum, item) => sum + item.subtotal, 0);
    const itemCount = items.reduce((sum, item) => sum + item.quantity, 0);
    
    return {
      itemCount,
      subtotal,
      uniqueItems: items.length
    };
  }
});

// 折扣计算selector
const discountSelector = selector({
  key: 'discount',
  get: async ({get}) => {
    const code = get(discountCodeAtom);
    const stats = get(cartStatsSelector);
    
    if (!code) {
      return { amount: 0, percentage: 0, valid: false };
    }

    try {
      const response = await fetch(`/api/discounts/${code}`);
      const discount = await response.json();
      
      if (discount.valid) {
        const amount = discount.type === 'percentage'
          ? stats.subtotal * (discount.value / 100)
          : discount.value;
          
        return {
          amount: Math.min(amount, stats.subtotal),
          percentage: discount.type === 'percentage' ? discount.value : 0,
          valid: true,
          code: discount.code
        };
      }
    } catch (error) {
      console.error('Discount validation failed:', error);
    }
    
    return { amount: 0, percentage: 0, valid: false };
  }
});

// 运费计算selector
const shippingCostSelector = selector({
  key: 'shippingCost',
  get: ({get}) => {
    const option = get(shippingOptionAtom);
    const stats = get(cartStatsSelector);
    
    if (!option) return 0;
    
    // 免费运费门槛
    if (stats.subtotal >= 100) {
      return 0;
    }
    
    return option.cost;
  }
});

// 总计selector
const cartTotalSelector = selector({
  key: 'cartTotal',
  get: ({get}) => {
    const stats = get(cartStatsSelector);
    const discount = get(discountSelector);
    const shippingCost = get(shippingCostSelector);
    const tax = (stats.subtotal - discount.amount) * 0.08; // 8% tax
    
    return {
      subtotal: stats.subtotal,
      discount: discount.amount,
      shipping: shippingCost,
      tax: Math.max(0, tax),
      total: stats.subtotal - discount.amount + shippingCost + Math.max(0, tax)
    };
  }
});

// 购物车操作hooks
function useCartActions() {
  const setCartItems = useSetRecoilState(cartItemsAtom);

  const addToCart = useRecoilCallback(({set, snapshot}) =>
    async (productId, quantity = 1, options = {}) => {
      const currentItems = await snapshot.getPromise(cartItemsAtom);
      
      const existingItemIndex = currentItems.findIndex(
        item => item.productId === productId && 
                JSON.stringify(item.options) === JSON.stringify(options)
      );

      if (existingItemIndex !== -1) {
        const newItems = [...currentItems];
        newItems[existingItemIndex].quantity += quantity;
        set(cartItemsAtom, newItems);
      } else {
        const newItem = {
          id: Date.now(),
          productId,
          quantity,
          options,
          addedAt: new Date().toISOString()
        };
        set(cartItemsAtom, [...currentItems, newItem]);
      }
    }
  );

  const removeFromCart = (itemId) => {
    setCartItems(prev => prev.filter(item => item.id !== itemId));
  };

  const updateQuantity = (itemId, quantity) => {
    if (quantity <= 0) {
      removeFromCart(itemId);
      return;
    }
    
    setCartItems(prev => 
      prev.map(item => 
        item.id === itemId ? { ...item, quantity } : item
      )
    );
  };

  const clearCart = () => {
    setCartItems([]);
  };

  return {
    addToCart,
    removeFromCart,
    updateQuantity,
    clearCart
  };
}

// 组件
function ShoppingCart() {
  const items = useRecoilValue(cartItemsWithDetailsSelector);
  const stats = useRecoilValue(cartStatsSelector);
  const total = useRecoilValue(cartTotalSelector);
  const { removeFromCart, updateQuantity, clearCart } = useCartActions();

  if (items.length === 0) {
    return (
      <div className="cart-empty">
        <p>Your cart is empty</p>
      </div>
    );
  }

  return (
    <div className="shopping-cart">
      <div className="cart-header">
        <h2>Shopping Cart ({stats.itemCount} items)</h2>
        <button onClick={clearCart}>Clear Cart</button>
      </div>

      <div className="cart-items">
        {items.map(item => (
          <CartItem
            key={item.id}
            item={item}
            onUpdateQuantity={updateQuantity}
            onRemove={removeFromCart}
          />
        ))}
      </div>

      <CartSummary total={total} />
      <DiscountSection />
      <ShippingSection />
    </div>
  );
}

function CartItem({ item, onUpdateQuantity, onRemove }) {
  return (
    <div className="cart-item">
      <img src={item.product.image} alt={item.product.name} />
      
      <div className="item-details">
        <h4>{item.product.name}</h4>
        <p>${item.product.price}</p>
        {Object.entries(item.options).map(([key, value]) => (
          <p key={key}>{key}: {value}</p>
        ))}
      </div>

      <div className="quantity-controls">
        <button onClick={() => onUpdateQuantity(item.id, item.quantity - 1)}>
          -
        </button>
        <span>{item.quantity}</span>
        <button onClick={() => onUpdateQuantity(item.id, item.quantity + 1)}>
          +
        </button>
      </div>

      <div className="item-total">
        ${item.subtotal.toFixed(2)}
      </div>

      <button onClick={() => onRemove(item.id)}>Remove</button>
    </div>
  );
}

function CartSummary({ total }) {
  return (
    <div className="cart-summary">
      <div className="summary-line">
        <span>Subtotal:</span>
        <span>${total.subtotal.toFixed(2)}</span>
      </div>
      
      {total.discount > 0 && (
        <div className="summary-line discount">
          <span>Discount:</span>
          <span>-${total.discount.toFixed(2)}</span>
        </div>
      )}
      
      <div className="summary-line">
        <span>Shipping:</span>
        <span>${total.shipping.toFixed(2)}</span>
      </div>
      
      <div className="summary-line">
        <span>Tax:</span>
        <span>${total.tax.toFixed(2)}</span>
      </div>
      
      <div className="summary-line total">
        <span>Total:</span>
        <span>${total.total.toFixed(2)}</span>
      </div>
    </div>
  );
}

function DiscountSection() {
  const [code, setCode] = useRecoilState(discountCodeAtom);
  const discount = useRecoilValue(discountSelector);

  return (
    <div className="discount-section">
      <h3>Discount Code</h3>
      
      <div className="discount-input">
        <input
          type="text"
          value={code}
          onChange={(e) => setCode(e.target.value)}
          placeholder="Enter discount code"
        />
      </div>
      
      {discount.valid && (
        <div className="discount-applied">
          <p>Discount applied: {discount.code}</p>
          <p>Save ${discount.amount.toFixed(2)}</p>
        </div>
      )}
      
      {code && !discount.valid && (
        <div className="discount-invalid">
          <p>Invalid discount code</p>
        </div>
      )}
    </div>
  );
}

最佳实践

1. Key命名规范

jsx
// 好的命名
const userAtom = atom({ key: 'user', default: null });
const todosAtom = atom({ key: 'todos', default: [] });
const isLoadingAtom = atom({ key: 'isLoading', default: false });

// 使用命名空间
const authUserAtom = atom({ key: 'auth/user', default: null });
const uiThemeAtom = atom({ key: 'ui/theme', default: 'light' });

// Family命名
const userFamily = atomFamily({ 
  key: 'user/byId', 
  default: id => ({ id, name: '', email: '' })
});

2. 状态结构设计

jsx
// 好:原子化设计
const userAtom = atom({ key: 'user', default: null });
const postsAtom = atom({ key: 'posts', default: [] });
const uiAtom = atom({ key: 'ui', default: { theme: 'light' } });

// 避免:过大的单一atom
const appStateAtom = atom({
  key: 'appState',
  default: {
    user: null,
    posts: [],
    ui: { theme: 'light' },
    // ... 大量状态
  }
});

3. 异步处理

jsx
// 使用Suspense处理异步selector
const asyncDataSelector = selector({
  key: 'asyncData',
  get: async ({get}) => {
    const userId = get(currentUserIdAtom);
    const response = await fetch(`/api/users/${userId}/data`);
    return response.json();
  }
});

function AsyncComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <AsyncDataDisplay />
    </Suspense>
  );
}

function AsyncDataDisplay() {
  const data = useRecoilValue(asyncDataSelector);
  return <div>{JSON.stringify(data)}</div>;
}

4. 性能优化

jsx
// 使用React.memo避免不必要渲染
const OptimizedComponent = React.memo(() => {
  const data = useRecoilValue(specificDataAtom);
  return <div>{data}</div>;
});

// 合理使用selector
const expensiveSelector = selector({
  key: 'expensive',
  get: ({get}) => {
    const data = get(dataAtom);
    // 复杂计算只在data变化时执行
    return expensiveCalculation(data);
  }
});

总结

Recoil提供了强大的原子化状态管理方案:

  1. 原子化设计:将状态拆分为独立的atoms
  2. 依赖追踪:自动优化组件重渲染
  3. 异步支持:原生支持异步状态和Suspense
  4. 强大工具:Effects、Family、Callback等
  5. 并发模式:完美支持React 18+特性

Recoil特别适合需要复杂状态依赖和异步处理的大型应用。