从简单到复杂:何时用 useState,何时用 useReducer?

在 React 开发中,状态管理是驱动组件交互和数据流的核心。随着项目复杂度的提升,开发者常常面临一个看似简单却至关重要的抉择:我该使用 useState,还是 useReducer

同样是一个 注册表单 (字段:usernameemailpasswordconfirmPasswordacceptTerms),用 useStateuseReducer 各写一遍,方便直观对比。

useState 版本

jsx 复制代码
import { useState } from 'react';

function RegisterFormUseState() {
  const [username, setUsername] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [acceptTerms, setAcceptTerms] = useState(false);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (password !== confirmPassword) {
      alert('两次密码不一致!');
      return;
    }
    console.log({ username, email, password, acceptTerms });
    resetForm();
  };

  const resetForm = () => {
    setUsername('');
    setEmail('');
    setPassword('');
    setConfirmPassword('');
    setAcceptTerms(false);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={username} onChange={(e) => setUsername(e.target.value)} placeholder="用户名" />
      <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="邮箱" />
      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="密码" />
      <input type="password" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} placeholder="确认密码" />
      <label>
        <input type="checkbox" checked={acceptTerms} onChange={(e) => setAcceptTerms(e.target.checked)} />
        同意条款
      </label>
      <button type="submit">注册</button>
      <button type="button" onClick={resetForm}>重置</button>
    </form>
  );
}

特点

  • 每个字段一个 useState
  • 重置表单需要逐个清空。
  • 字段多了会有很多重复 setter。

useReducer 版本

jsx 复制代码
import { useReducer } from 'react';

const initialState = {
  username: '',
  email: '',
  password: '',
  confirmPassword: '',
  acceptTerms: false,
};

function reducer(state, action) {
  switch (action.type) {
    case 'updateField':
      return { ...state, [action.field]: action.value };
    case 'reset':
      return initialState;
    default:
      return state;
  }
}

function RegisterFormUseReducer() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (state.password !== state.confirmPassword) {
      alert('两次密码不一致!');
      return;
    }
    console.log(state);
    dispatch({ type: 'reset' });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={state.username}
        onChange={(e) => dispatch({ type: 'updateField', field: 'username', value: e.target.value })}
        placeholder="用户名"
      />
      <input
        value={state.email}
        onChange={(e) => dispatch({ type: 'updateField', field: 'email', value: e.target.value })}
        placeholder="邮箱"
      />
      <input
        type="password"
        value={state.password}
        onChange={(e) => dispatch({ type: 'updateField', field: 'password', value: e.target.value })}
        placeholder="密码"
      />
      <input
        type="password"
        value={state.confirmPassword}
        onChange={(e) => dispatch({ type: 'updateField', field: 'confirmPassword', value: e.target.value })}
        placeholder="确认密码"
      />
      <label>
        <input
          type="checkbox"
          checked={state.acceptTerms}
          onChange={(e) => dispatch({ type: 'updateField', field: 'acceptTerms', value: e.target.checked })}
        />
        同意条款
      </label>
      <button type="submit">注册</button>
      <button type="button" onClick={() => dispatch({ type: 'reset' })}>重置</button>
    </form>
  );
}

特点

  • 所有字段集中管理在 state
  • 重置、动态字段处理方便。
  • 更新逻辑统一在 reducer,可维护性高。

总结 : 为什么要用 useReducer

  • 当你有多个状态值 要管理,且它们之间有关联(比如同时更新多个字段)
  • 当更新逻辑复杂,用 useState 会很混乱
  • 想让状态更新逻辑更清晰、集中、可测试
相关推荐
颜渊呐几秒前
Vue3 + Less 实现动态圆角 TabBar:从代码到优化实践
前端·css
PineappleCoder4 分钟前
pnpm 凭啥吊打 npm/Yarn?前端包管理的 “硬链接魔法”,破解三大痛点
前端·javascript·前端工程化
fruge8 分钟前
前端文档自动化:用 VitePress 搭建团队技术文档(含自动部署)
运维·前端·自动化
CoolerWu1 小时前
TRAE SOLO实战成功展示&总结:一个所见即所得的笔记软体
前端·javascript
Cassie燁1 小时前
el-button源码解读1——为什么组件最外层套的是Vue内置组件Component
前端·vue.js
vx_bscxy3221 小时前
告别毕设焦虑!Python 爬虫 + Java 系统 + 数据大屏,含详细开发文档 基于web的图书管理系统74010 (上万套实战教程,赠送源码)
java·前端·课程设计
北极糊的狐1 小时前
Vue3 子组件修改父组件传递的对象并同步的方法汇总
前端·javascript·vue.js
spionbo1 小时前
Vue3 前端分页功能实现的技术方案及应用实例解析
前端
AI绘画小331 小时前
Web 安全核心真相:别太相信任何人!40 个漏洞挖掘实战清单,直接套用!
前端·数据库·测试工具·安全·web安全·网络安全·黑客
7***n751 小时前
前端设计模式详解
前端·设计模式·状态模式