useSetRecoilState #

什么是 useSetRecoilState? #

useSetRecoilState 是一个只写 Hook,用于获取设置 Recoil 状态的函数。当组件只需要修改状态而不需要读取时,使用这个 Hook 可以避免不必要的重渲染。

jsx
const setValue = useSetRecoilState(state);

基本用法 #

设置状态 #

jsx
import { atom, useSetRecoilState } from 'recoil';

const countState = atom({
  key: 'countState',
  default: 0,
});

function IncrementButton() {
  const setCount = useSetRecoilState(countState);
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Increment
    </button>
  );
}

重置状态 #

jsx
function ResetButton() {
  const setCount = useSetRecoilState(countState);
  
  return (
    <button onClick={() => setCount(0)}>
      Reset
    </button>
  );
}

性能优势 #

避免订阅状态变化 #

使用 useSetRecoilState 的组件不会在状态变化时重渲染:

jsx
function OptimizedButton() {
  const setCount = useSetRecoilState(countState);
  
  console.log('This only logs once on mount');
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Increment
    </button>
  );
}

对比使用 useRecoilState

jsx
function LessOptimizedButton() {
  const [count, setCount] = useRecoilState(countState);
  
  console.log('This logs on every count change');
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Increment
    </button>
  );
}

更新方式 #

直接设置值 #

jsx
const setCount = useSetRecoilState(countState);

setCount(10);
setCount(0);

使用函数更新 #

jsx
setCount(prev => prev + 1);
setCount(prev => prev * 2);

更新对象 #

jsx
const setUser = useSetRecoilState(userState);

setUser({ name: 'John', email: 'john@example.com' });
setUser(prev => ({ ...prev, name: 'Jane' }));

更新数组 #

jsx
const setTodos = useSetRecoilState(todoListState);

setTodos(prev => [...prev, newTodo]);
setTodos(prev => prev.filter(todo => todo.id !== id));

实战示例:表单提交 #

jsx
import { atom, useSetRecoilState, useRecoilValue } from 'recoil';

const formState = atom({
  key: 'formState',
  default: {
    username: '',
    email: '',
  },
});

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

function SubmitButton() {
  const setSubmitted = useSetRecoilState(submittedState);
  const setForm = useSetRecoilState(formState);
  
  const handleSubmit = () => {
    setSubmitted(true);
    setForm({ username: '', email: '' });
  };
  
  return (
    <button onClick={handleSubmit}>
      Submit
    </button>
  );
}

实战示例:通知系统 #

jsx
import { atom, useSetRecoilState } from 'recoil';

const notificationsState = atom({
  key: 'notifications',
  default: [],
});

function useNotifications() {
  const setNotifications = useSetRecoilState(notificationsState);
  
  const addNotification = (message, type = 'info') => {
    const id = Date.now();
    setNotifications(prev => [
      ...prev,
      { id, message, type, timestamp: Date.now() },
    ]);
    
    setTimeout(() => {
      removeNotification(id);
    }, 5000);
  };
  
  const removeNotification = (id) => {
    setNotifications(prev => prev.filter(n => n.id !== id));
  };
  
  const clearAll = () => {
    setNotifications([]);
  };
  
  return { addNotification, removeNotification, clearAll };
}

function NotificationButtons() {
  const { addNotification, clearAll } = useNotifications();
  
  return (
    <div>
      <button onClick={() => addNotification('Success!', 'success')}>
        Add Success
      </button>
      <button onClick={() => addNotification('Error!', 'error')}>
        Add Error
      </button>
      <button onClick={clearAll}>
        Clear All
      </button>
    </div>
  );
}

实战示例:主题切换 #

jsx
import { atom, useSetRecoilState, useRecoilValue } from 'recoil';

const themeState = atom({
  key: 'theme',
  default: 'light',
});

function ThemeToggle() {
  const setTheme = useSetRecoilState(themeState);
  
  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };
  
  return (
    <button onClick={toggleTheme}>
      Toggle Theme
    </button>
  );
}

function ThemeDisplay() {
  const theme = useRecoilValue(themeState);
  
  return <div>Current theme: {theme}</div>;
}

实战示例:购物车操作 #

jsx
import { atom, useSetRecoilState } from 'recoil';

const cartState = atom({
  key: 'cart',
  default: [],
});

function ProductCard({ product }) {
  const setCart = useSetRecoilState(cartState);
  
  const addToCart = () => {
    setCart(prev => {
      const existing = prev.find(item => item.id === product.id);
      if (existing) {
        return prev.map(item =>
          item.id === product.id
            ? { ...item, quantity: item.quantity + 1 }
            : item
        );
      }
      return [...prev, { ...product, quantity: 1 }];
    });
  };
  
  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <button onClick={addToCart}>Add to Cart</button>
    </div>
  );
}

function ClearCartButton() {
  const setCart = useSetRecoilState(cartState);
  
  return (
    <button onClick={() => setCart([])}>
      Clear Cart
    </button>
  );
}

与 useCallback 结合 #

jsx
import { useCallback } from 'react';
import { useSetRecoilState } from 'recoil';

function OptimizedComponent() {
  const setCount = useSetRecoilState(countState);
  
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, [setCount]);
  
  const decrement = useCallback(() => {
    setCount(c => c - 1);
  }, [setCount]);
  
  const reset = useCallback(() => {
    setCount(0);
  }, [setCount]);
  
  return (
    <div>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

与自定义 Hook 结合 #

jsx
function useCounterActions() {
  const setCount = useSetRecoilState(countState);
  
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, [setCount]);
  
  const decrement = useCallback(() => {
    setCount(c => c - 1);
  }, [setCount]);
  
  const reset = useCallback(() => {
    setCount(0);
  }, [setCount]);
  
  const set = useCallback((value) => {
    setCount(value);
  }, [setCount]);
  
  return { increment, decrement, reset, set };
}

function CounterControls() {
  const { increment, decrement, reset } = useCounterActions();
  
  return (
    <div>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

TypeScript 支持 #

tsx
import { atom, useSetRecoilState } from 'recoil';

interface User {
  id: number;
  name: string;
  email: string;
}

const userState = atom<User | null>({
  key: 'userState',
  default: null,
});

function LoginButton() {
  const setUser = useSetRecoilState(userState);
  
  const handleLogin = async () => {
    const user = await login();
    setUser(user);
  };
  
  return <button onClick={handleLogin}>Login</button>;
}

完整示例:用户认证 #

jsx
import { atom, useSetRecoilState, useRecoilValue } from 'recoil';

const authState = atom({
  key: 'auth',
  default: {
    isLoggedIn: false,
    user: null,
    token: null,
  },
});

function useAuth() {
  const setAuth = useSetRecoilState(authState);
  
  const login = async (credentials) => {
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(credentials),
      });
      const data = await response.json();
      
      setAuth({
        isLoggedIn: true,
        user: data.user,
        token: data.token,
      });
      
      return { success: true };
    } catch (error) {
      return { success: false, error };
    }
  };
  
  const logout = () => {
    setAuth({
      isLoggedIn: false,
      user: null,
      token: null,
    });
  };
  
  return { login, logout };
}

function LoginButton() {
  const { login } = useAuth();
  
  return (
    <button onClick={() => login({ username: 'user', password: 'pass' })}>
      Login
    </button>
  );
}

function LogoutButton() {
  const { logout } = useAuth();
  
  return <button onClick={logout}>Logout</button>;
}

function AuthStatus() {
  const auth = useRecoilValue(authState);
  
  return (
    <div>
      {auth.isLoggedIn ? (
        <span>Logged in as {auth.user.name}</span>
      ) : (
        <span>Not logged in</span>
      )}
    </div>
  );
}

总结 #

useSetRecoilState 的核心要点:

特点 说明
只写 只能修改状态,不能读取
无订阅 状态变化不会触发重渲染
性能 适用于只需要修改状态的组件
返回值 返回设置函数

下一步,让我们学习 useResetRecoilState,了解重置状态的 Hook。

最后更新:2026-03-28