工程实践 React

事件处理与状态更新

表单元素的 value 由 React state 控制的组件称为"受控组件"。

发布于 2026/02/26 1 分钟

掌握事件处理,让应用”动”起来

事件处理基础

基本语法

function App() {
  const handleClick = () => {
    alert('点击了按钮!');
  };

  return (
    <button onClick={handleClick}>
      点击我
    </button>
  );
}

传递参数

function App() {
  const handleClick = (message) => {
    alert(message);
  };

  return (
    <button onClick={() => handleClick('Hello!')}>
      点击我
    </button>
  );
}

使用事件对象

function App() {
  const handleChange = (event) => {
    console.log('输入值:', event.target.value);
    console.log('事件类型:', event.type);
  };

  return (
    <input onChange={handleChange} />
  );
}

常见事件类型

表单事件

function Form() {
  const handleSubmit = (e) => {
    e.preventDefault(); // 阻止表单默认提交
    console.log('表单提交');
  };

  const handleFocus = (e) => {
    console.log('获得焦点');
  };

  const handleBlur = (e) => {
    console.log('失去焦点');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        onFocus={handleFocus}
        onBlur={handleBlur}
      />
      <button type="submit">提交</button>
    </form>
  );
}

鼠标事件

function MouseDemo() {
  const handleMouseEnter = (e) => {
    console.log('鼠标进入');
  };

  const handleMouseLeave = (e) => {
    console.log('鼠标离开');
  };

  const handleMouseMove = (e) => {
    console.log(`位置: ${e.clientX}, ${e.clientY}`);
  };

  return (
    <div
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
      onMouseMove={handleMouseMove}
      style={{ padding: 20, background: '#f0f0f0' }}
    >
      鼠标事件区域
    </div>
  );
}

键盘事件

function KeyboardDemo() {
  const handleKeyDown = (e) => {
    console.log('按键:', e.key);
    console.log('按键码:', e.code);

    // 常见用法
    if (e.key === 'Enter') {
      console.log('按下回车键');
    }
    if (e.ctrlKey && e.key === 's') {
      e.preventDefault();
      console.log('Ctrl+S 保存');
    }
  };

  return (
    <input
      onKeyDown={handleKeyDown}
      placeholder="输入一些文字..."
    />
  );
}

受控组件

表单元素的 value 由 React state 控制的组件称为”受控组件”。

输入框

function InputDemo() {
  const [value, setValue] = useState('');

  return (
    <input
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

文本域

function TextareaDemo() {
  const [content, setContent] = useState('');

  return (
    <textarea
      value={content}
      onChange={(e) => setContent(e.target.value)}
      rows={4}
    />
  );
}

下拉选择

function SelectDemo() {
  const [framework, setFramework] = useState('react');

  return (
    <select
      value={framework}
      onChange={(e) => setFramework(e.target.value)}
    >
      <option value="react">React</option>
      <option value="vue">Vue</option>
      <option value="angular">Angular</option>
    </select>
  );
}

复选框

function CheckboxDemo() {
  const [isAgreed, setIsAgreed] = useState(false);

  return (
    <label>
      <input
        type="checkbox"
        checked={isAgreed}
        onChange={(e) => setIsAgreed(e.target.checked)}
      />
      我同意条款
    </label>
  );
}

单选按钮

function RadioDemo() {
  const [gender, setGender] = useState('male');

  return (
    <div>
      <label>
        <input
          type="radio"
          name="gender"
          value="male"
          checked={gender === 'male'}
          onChange={(e) => setGender(e.target.value)}
        />

      </label>
      <label>
        <input
          type="radio"
          name="gender"
          value="female"
          checked={gender === 'female'}
          onChange={(e) => setGender(e.target.value)}
        />

      </label>
    </div>
  );
}

表单综合示例

function RegistrationForm() {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    password: '',
    gender: 'male',
    agree: false
  });

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('提交数据:', formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>用户名:</label>
        <input
          type="text"
          name="username"
          value={formData.username}
          onChange={handleChange}
        />
      </div>

      <div>
        <label>邮箱:</label>
        <input
          type="email"
          name="email"
          value={formData.email}
          onChange={handleChange}
        />
      </div>

      <div>
        <label>密码:</label>
        <input
          type="password"
          name="password"
          value={formData.password}
          onChange={handleChange}
        />
      </div>

      <div>
        <label>性别:</label>
        <select name="gender" value={formData.gender} onChange={handleChange}>
          <option value="male">男</option>
          <option value="female">女</option>
        </select>
      </div>

      <div>
        <label>
          <input
            type="checkbox"
            name="agree"
            checked={formData.agree}
            onChange={handleChange}
          />
          我同意服务条款
        </label>
      </div>

      <button type="submit">注册</button>
    </form>
  );
}

非受控组件

表单元素的 value 由 DOM 本身控制的组件称为”非受控组件”。

function UncontrolledInput() {
  const inputRef = useRef(null);

  const handleSubmit = () => {
    alert('输入的值: ' + inputRef.current.value);
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleSubmit}>获取值</button>
    </div>
  );
}

事件处理的最佳实践

1. 事件处理函数提取

// ❌ 内联写法(复杂逻辑时不推荐)
<button onClick={() => { setCount(count + 1); setTotal(total + count); }}>

// ✅ 提取为独立函数
const handleClick = () => {
  setCount(count + 1);
  setTotal(total + count);
};

<button onClick={handleClick}>

2. 使用 useCallback 优化

import { useCallback } from 'react';

function App() {
  const handleClick = useCallback(() => {
    console.log('点击');
  }, []); // 依赖数组为空,函数不会改变

  return <button onClick={handleClick}>点击</button>;
}

3. 避免频繁创建函数

function List({ items, onItemClick }) {
  return (
    <ul>
      {items.map(item => (
        <li
          key={item.id}
          // ❌ 每次渲染都会创建新函数
          onClick={() => onItemClick(item.id)}
        >
          {item.name}
        </li>
      ))}
    </ul>
  );
}

总结

本章我们学习了:

  • React 事件处理的基本语法
  • 常见事件类型(表单、鼠标、键盘)
  • 受控组件与非受控组件
  • 表单处理的最佳实践
  • 事件处理的性能优化

下一章我们将学习条件渲染与列表渲染。