系列回顾:
在前面的文章中,我们已经掌握了State、Props、事件处理、列表渲染和条件渲染。我们的应用已经能展示动态内容并响应用户的点击。现在,我们要 tackling 一个非常常见的需求:如何获取用户在表单输入框(<input>)里输入的内容?比如,在一个登录页面,我们需要拿到用户输入的用户名和密码。
欢迎来到React学习的第七站!
在传统的HTML和jQuery中,我们通常是在需要的时候(比如点击提交按钮时)才去DOM中“读取”输入框的值。但在React中,我们有一种更推荐、更“React”的方式,叫做受控组件 (Controlled Components)。
什么是受控组件?
简单来说,一个受控组件就是:一个表单元素(如<input>, <textarea>, <select>),它的值完全由React的State来“控制”。
它的工作流程是这样的:
- 我们用
useState创建一个 State 变量,用来存储输入框的值。 - 我们把这个 State 变量的值,通过
value属性,赋给输入框。 - 我们给输入框绑定
onChange事件。每当用户在输入框里打字时,onChange事件就会被触发。 - 在
onChange的事件处理函数里,我们获取输入框的最新值,然后调用setState函数来更新我们的 State。 - 由于 State 发生了变化,React 会重新渲染组件,输入框的
value也随之更新,显示出最新的内容。
听起来有点绕?别担心,我们通过一个实战案例来走一遍,你马上就会明白。
核心思想: 输入框里显示什么,不再是输入框自己说了算,而是由React的State说了算。实现了数据(State)和视图(UI)的完全同步。
实战:创建一个简单的用户名输入框
我们的目标是:创建一个输入框,用户在里面输入的任何内容,都会被实时地显示在页面的另一个地方。
第一步:准备App.jsx
老规矩,我们先搭好架子,并用useState创建一个username的State,初始值为空字符串 ''。
import { useState } from 'react';
import './App.css';function App() {const [username, setUsername] = useState('');return (<div><h1>受控组件入门</h1><label>用户名:{/* 我们将在这里创建受控的 input */}</label><hr /><h3>你输入的内容是: {username}</h3></div>);
}export default App;
第二步:创建受控的<input>
现在,我们来创建这个输入框,并把它和我们的username State关联起来。
修改return部分的代码:
function App() {const [username, setUsername] = useState('');// 3. 定义 onChange 事件处理函数const handleUsernameChange = (event) => {// 4. 从事件对象中获取输入框的最新值const newValue = event.target.value;// 5. 更新 statesetUsername(newValue);};return (<div><h1>受控组件入门</h1><label>用户名:<input type="text" // 1. 将 state 的值绑定到 input 的 valuevalue={username}// 2. 监听 input 的内容变化onChange={handleUsernameChange}/></label><hr /><h3>你输入的内容是: {username}</h3></div>);
}
代码解释(请严格按照数字顺序理解):
value={username}: 我们把username这个State的值,强制赋给了输入框的value属性。现在,这个输入框显示什么,完全由username决定。onChange={handleUsernameChange}: 我们监听输入框的change事件。只要用户在里面打一个字,这个事件就会被触发,并调用handleUsernameChange函数。- 我们定义了
handleUsernameChange函数。这个函数会自动接收一个事件对象 (event) 作为参数。 event.target.value: 这是获取输入框当前值的标准方式。event.target指向触发事件的DOM元素(也就是那个<input>),.value就是它的值。setUsername(newValue): 我们调用更新函数,把获取到的新值赋给username这个State。
完整的流程闭环了!
用户打字 -> onChange触发 -> handleUsernameChange执行 -> setUsername更新State -> React重新渲染 -> 输入框的value被更新为最新的State值。
第三步:测试效果
保存文件,回到浏览器。现在,尝试在输入框里打字。你会发现,下面的“你输入的内容是:”那一行,会实时地、一字不差地显示出你输入的内容。
你已经成功掌握了受控组件!
为什么推荐使用受控组件?
- 唯一数据源 (Single Source of Truth): 组件的状态都由React State统一管理,代码逻辑更清晰,调试更方便。
- 实时校验: 因为你能实时拿到输入值,所以可以轻松地做一些即时校验,比如限制输入长度、禁止输入特殊字符等。
- 动态交互: 可以根据输入的值,动态地改变其他UI元素的状态,比如当密码长度小于6位时,提交按钮置灰。
处理多个输入框
如果一个表单有多个输入框(比如用户名和密码),难道要为每个输入框都写一个单独的事件处理函数吗?当然不用!我们可以用一个更巧妙的方式来处理。
实战:一个简单的登录表单
import { useState } from 'react';
import './App.css';function App() {const [form, setForm] = useState({username: '',password: ''});const handleChange = (event) => {const { name, value } = event.target; // 解构获取 name 和 valuesetForm(prevForm => ({...prevForm, // 复制旧的 form 对象[name]: value // 使用计算属性名动态更新对应的字段}));};const handleSubmit = (event) => {event.preventDefault(); // 阻止表单默认的提交刷新行为alert(`登录中... 用户名: ${form.username}, 密码: ${form.password}`);};return (<form onSubmit={handleSubmit}><h1>登录表单</h1><div><label>用户名:</label><input type="text" name="username" value={form.username} onChange={handleChange} /></div><div><label>密码:</label><input type="password" name="password" value={form.password} onChange={handleChange} /></div><button type="submit">登录</button></form>);
}export default App;
代码解释:
- 我们用一个对象来作为State,
{username: '', password: ''}。 - 给每个
<input>添加了一个name属性,且name的值与State对象中的键名完全对应。 - 我们只用了一个
handleChange函数。在函数内部,通过event.target.name可以知道是哪个输入框触发了事件,event.target.value是它的值。 [name]: value这是JavaScript的计算属性名语法,它允许我们动态地设置对象的键。如果name是"username",这就相当于username: value。- 我们用
<form>和onSubmit来处理表单的提交。event.preventDefault()是防止页面刷新的关键。
总结与思考
今天,我们攻克了React中非常重要的一个环节——表单处理。你已经掌握了:
- 受控组件的核心概念:UI的值由React State控制。
- 如何使用
useState,value和onChange三件套,实现对单个输入框的控制。 - 如何用一个State对象和一个事件处理函数,优雅地管理多个输入框。
现在,我们的应用已经可以和用户进行深度的数据交互了。但是,我们所有的数据都还停留在前端。一个真正的应用,需要和后端服务器进行通信,去获取和提交数据。
在下一篇文章 《React副作用处理:useEffect入门,组件加载后如何请求API数据?》 中,我们将学习如何使用useEffect这个强大的Hook,在组件渲染完成后去执行一些“副作用”操作,比如从一个公开的API获取数据并展示在页面上。我们下期再会!