Forms in React : From Inputs to Controlled Components
Forms in React: From Inputs to Controlled Components
React 中的表单:从输入框到受控组件
You have probably written HTML forms before, and so the structure below resonates with you. Perhaps you even smile because, this one, you understand. 你可能以前写过 HTML 表单,所以下面的结构对你来说很熟悉。也许你甚至会会心一笑,因为这个你很了解。
<form>
<input type="text"/>
<button>Submit</button>
</form>
If you have done this, you know what happens when you click the button. The whole form reloads, the changes or inputs are cleared. This is the default behavior of forms in HTML. 如果你写过这段代码,你就会知道点击按钮时会发生什么:整个表单会重新加载,所有的更改或输入内容都会被清除。这是 HTML 表单的默认行为。
In React, we handle every step and every stage so that we have control over the data and the behavior of the form and data. The above signature represents what we call UNCONTROLLED INPUT. This means that there isn’t a single source of truth to the value of this field, hence it can change to anything, and any value. 在 React 中,我们处理每一个步骤和阶段,以便能够控制数据以及表单和数据的行为。上述写法代表了我们所说的“非受控输入”(UNCONTROLLED INPUT)。这意味着该字段的值没有单一的事实来源(single source of truth),因此它可以变成任何值。
In addition to the above attributes, we will add value and onChange props to the input element as below:
除了上述属性外,我们还将在 input 元素中添加 value 和 onChange 属性,如下所示:
<input type="text" value={} onChange={}/>
value represents the content of the input field e.g. the name text that the user enters in a Name field. onChange is the function that will be triggered everytime the input changes. Whenever a key is pressed within this field, this function will be invoked.
value 代表输入框的内容,例如用户在“姓名”字段中输入的文本。onChange 是每次输入发生变化时都会触发的函数。每当在该字段中按下按键时,此函数就会被调用。
Controlled inputs have their values set and manipulated by states, as we saw in Part 1 of the series. Uncontrolled inputs on the other hand do not have a manager that will dictate what goes into the field and when. 受控输入的数值由状态(state)设置和操作,正如我们在本系列第一部分所看到的那样。相反,非受控输入没有一个管理者来决定字段中输入什么内容以及何时输入。
Now let’s write our first React Input, we’ll keep it simple. 现在让我们编写第一个 React 输入框,保持简单。
import { useState } from "react"
function Form(){
const [name, setName] = useState("")
return(
<input type="text" value={name} onChange={(event) => setName(event.target.value)} />
)
}
Let’s look at what happens in the above. We have declared a state [name, setName]. name is the state variable, setName is a function used to update the variable. We then initialized an input element with properties value and onChange.
让我们看看上面发生了什么。我们声明了一个状态 [name, setName]。name 是状态变量,setName 是用于更新该变量的函数。然后,我们初始化了一个带有 value 和 onChange 属性的 input 元素。
Note that, when the value of an input is set, that will always be the value even if you type something into the box. That is the essence of controlled input. The onChange property will then fire when the user enters text into the textfield. Doing this triggers the setName function which sets the name value to whatever the user enters. That value becomes the new name which is tied to the textfield’s value, hence the value changes to reflect the user’s input. That is the whole flow of Controlled Inputs. This is how React controls inputs.
请注意,当 input 的值被设置后,即使你在框中输入内容,它也始终保持该值。这就是受控输入的本质。当用户在文本框中输入文本时,onChange 属性会被触发。这会调用 setName 函数,将 name 的值设置为用户输入的内容。该值成为新的 name,并与文本框的值绑定,因此值会发生变化以反映用户的输入。这就是受控输入的完整流程。这就是 React 控制输入的方式。
Handling Form Submission
处理表单提交
function Form() {
const [name, setName] = useState("");
function handleSubmit(event) {
event.preventDefault();
console.log(name);
}
return (
<form onSubmit={handleSubmit}>
<input type="text" value={name} onChange={(event) => setName(event.target.value)} />
<button type="submit">Submit</button>
</form>
);
}
This is a complete implementation of a form implementation in React. We have already gone through the input flow. Now we have just wrapped the whole element inside a form and added a submit button. Notice there is a function we have added handleSubmit(event){}. This function will be executed when the submit button is pressed.
这是一个 React 表单实现的完整示例。我们已经了解了输入流程,现在只需将整个元素包裹在 <form> 中并添加一个提交按钮。注意我们添加了一个函数 handleSubmit(event){}。当按下提交按钮时,此函数将被执行。
Like we have mentioned before, the normal execution flow of forms is such that, the whole page will reload and the form content will be lost. Suppose you want to manipulate or manage the form before submission, then you add the event.preventDefault() line. This stops the default workflow of form submission such that the page won’t reload and your changes won’t be lost. The event property is passed automatically into the handleSubmit function.
正如我们之前提到的,表单的正常执行流程会导致整个页面重新加载,表单内容也会丢失。如果你想在提交前操作或管理表单,就需要添加 event.preventDefault() 这一行。这会阻止表单提交的默认工作流,从而使页面不会重新加载,你的更改也不会丢失。event 属性会自动传递给 handleSubmit 函数。
But … What if you have more fields? Sure, you can have more than one state variables e.g. 但是……如果你有更多的字段怎么办?当然,你可以拥有多个状态变量,例如:
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
This still works, but notice that we have repeated the useState. Of course optimization may not be the first thing to think about as a newbie, but once you get the hang of things, consider doing this instead:
这仍然有效,但请注意我们重复使用了 useState。当然,对于初学者来说,优化可能不是首要考虑的事情,但一旦你掌握了窍门,可以考虑这样做:
const [formData, setFormData] = useState({
name:"",
email:"",
password:""
})
Here we have compressed the definition to only have one useState, making our code more concise.
在这里,我们将定义压缩为仅使用一个 useState,使代码更加简洁。
Input Types
输入类型
Just like in HTML, we have different types on inputs and their implementation follow the same logic but with a few minor tweaks: 就像在 HTML 中一样,我们有不同类型的输入,它们的实现遵循相同的逻辑,但有一些细微的调整:
Checkbox
const [agreed, setAgreed] = useState(false);
<input type="checkbox" checked={agreed} onChange={(event) => setAgreed(event.target.checked)} />
Here we use event.target.checked instead of event.target.value.
这里我们使用 event.target.checked 而不是 event.target.value。
Select
<select value={country} onChange={(event) => setCountry(event.target.value)} >
<option value="">Select a country</option>
<option value="kenya">Kenya</option>
<option value="uganda">Uganda</option>
</select>
Textarea
<textarea value={message} onChange={(event) => setMessage(event.target.value)} />
Form Validation
表单验证
For forms to be complete, validation must be enforced to ensure correct and proper data has been entered. The basic validation we know is that a form shouldn’t be submitted with empty data or fields. That is exactly where validation comes in. An example of validation in the handleSubmit function is as follows:
为了使表单完整,必须强制执行验证,以确保输入了正确且合适的数据。我们所知的基本验证是表单不应在数据或字段为空的情况下提交。这正是验证发挥作用的地方。在 handleSubmit 函数中进行验证的一个示例如下:
const [error, setError] = useState("");
function handleSubmit(event) {
event.preventDefault();
if (!formData.name.trim()) {
setError("Name is required");
return;
}
if (!formData.email.includes("@")) {
setError("Enter a valid email");
return;
}
console.log(formData);
}
And with that, you have the basics to build a react form and implement validation. Practice more until you grasp it all. 有了这些,你就掌握了构建 React 表单和实现验证的基础知识。多加练习,直到完全掌握。
Exercise
练习
Build the form as below and implement everything we have gone through. If you get stuck, refer or engage in the comments. 构建如下表单并实现我们所讲的所有内容。如果遇到困难,请参考本文或在评论区交流。
┌─────────────────────────┐
│ Create an account │
│ │
│ Name │
│ [____________________] │
│ │
│ Email │
│ [____________________] │
│ │
│ Password │
│ [____________________] │
│ │
│ ☑ I agree to the terms │
│ │
│ [ Create Account ] │
└─────────────────────────┘
This will test your knowledge on: 这将测试你对以下知识点的掌握程度:
- useState
- Controlled inputs (受控输入)
- onChange
- onSubmit
- preventDefault
- Multiple fields (多字段处理)
- Checkbox handling (复选框处理)
- Validation (验证)
- Error messages (错误信息)
Conclusion
总结
We gone through form… 我们已经了解了表单……