不使用库在 React 中使用表单
在 JavaScript 中处理表单可能是一项艰巨的任务,在本文中我们将学习如何处理它们。
不受控制的输入
首先我们需要讨论一下非受控输入,这里我说的输入,其实也包括 select 或 textarea。这是输入的默认状态,在这种情况下,我们不做任何特殊处理,让浏览器自行处理它的值。
function Form() {
const [message, setMessage] = React.useState("");
function handleSubmit(event) {
event.preventDefault();
setMessage(event.target.elements.message.value);
event.target.reset();
}
return (
<>
<p>{message}</p>
<form onSubmit={handleSubmit}>
<input name="message" type="text" />
</form>
</>
);
}
正如我们在上面的例子中看到的,message
在用户提交表单后,我们使用输入的值来更新我们的状态,按下enter
,并重置输入值,我们只需使用reset()
表单的方法重置整个表单。
这是正常的 DOM 操作,用于读取值并重置它,对 React 来说没有什么特别的。
受控输入
现在让我们来谈谈有趣的部分,控制器输入/选择/文本区域是一个值绑定到状态的元素,我们需要更新状态来更新用户看到的输入值。
function Form() {
const [message, setMessage] = React.useState("");
function handleSubmit(event) {
event.preventDefault();
setMessage("");
}
function handleChange(event) {
setMessage(event.target.value);
}
return (
<>
<p>{message}</p>
<form onSubmit={handleSubmit}>
<input
name="message"
type="text"
onChange={handleChange}
value={message}
/>
</form>
</>
);
}
我们的示例将input
值设置为message
并附加一个onChange
我们称之为的事件监听器handleChange
,在这个函数内部我们需要event.target.value
接收输入的新值,即当前值加上用户输入的值,我们调用它setMessage
来更新我们的组件状态,这将更新标签的内容p
和标签的值input
以匹配新状态。
如果我们想要重置输入,我们可以调用setMessage("")
,就像在中所做的那样handleSubmit
,这将重置状态并重置输入的值和p
内容。
添加简单验证
_
现在让我们添加一个简单的验证,复杂的验证类似但有更多的规则,在这种情况下,如果使用特殊字符,我们将使输入无效。
function Form() {
const [message, setMessage] = React.useState("");
const [error, setError] = React.useState(null);
function handleSubmit(event) {
event.preventDefault();
setError(null);
setMessage("");
}
function handleChange(event) {
const value = event.target.value;
if (value.includes("_")) setError("You cannot use an underscore");
else setError(null);
setMessage(value);
}
return (
<>
<p>{message}</p>
<form onSubmit={handleSubmit}>
<input
id="message"
name="message"
type="text"
onChange={handleChange}
value={message}
/>
{error && (
<label style={{ color: "red" }} htmlFor="message">
{error}
</label>
)}
</form>
</>
);
}
我们创建两个状态,一个用于输入值,另一个用于错误信息。和之前一样,handleSubmit
我们将message
状态重置为空字符串,另外,我们将error
状态重置为null
。
在 中,handleChange
我们将读取输入的新值并检查是否存在下划线。如果发现下划线,我们将错误状态更新为消息;"You cannot use an underscore"
如果不存在,我们将错误状态设置为null
。验证完成后,我们将message
使用新值更新状态。
在返回的 UI 中,我们将检查是否存在,error
并渲染一个label
指向输入框的红色文本,并在其中显示错误消息。错误信息位于标签内,以便用户点击它并将焦点移至输入框。
控制文本区域
之前我说过使用input
和textarea
是相似的,事实上也是如此,让我们将渲染的元素更改为textarea
,上面的代码将继续工作而无需任何其他更改,如下所示。
function Form() {
const [message, setMessage] = React.useState("");
const [error, setError] = React.useState(null);
function handleSubmit(event) {
event.preventDefault();
}
function handleChange(event) {
const value = event.target.value;
if (value.includes("_")) {
setError("You cannot use an underscore");
} else {
setError(null);
setMessage(value);
}
}
return (
<>
<p>{message}</p>
<form onSubmit={handleSubmit}>
<textarea
id="message"
name="message"
onChange={handleChange}
value={message}
/>
{error && (
<label style={{ color: "red" }} htmlFor="message">
{error}
</label>
)}
</form>
</>
);
}
虽然通常textarea
是一个具有内部内容的元素,就像<textarea>Content here</textarea>
在 React 中一样,为了改变值,我们使用value
像输入和onChange
事件一样的 prop,使输入和文本区域之间的变化相似。
控制选择
现在我们来谈谈select
。与 一样,textarea
你将其视为普通的input
,传递一个value
带有选定值的 prop ,并使用 监听值的变化onChange
。传递给 的值select
应该与其中一个选项的值匹配,以将其中一个选项显示为当前选定的选项。
function Form() {
const [option, setOption] = React.useState(null);
const [error, setError] = React.useState(null);
function handleSubmit(event) {
event.preventDefault();
}
function handleChange(event) {
setOption(event.target.value);
}
function handleResetClick() {
setOption(null);
}
function handleHooksClick() {
setOption("hooks");
}
return (
<>
<p>{option}</p>
<form onSubmit={handleSubmit}>
<select onChange={handleChange} value={option}>
<option value="classes">Classes</option>
<option value="flux">Flux</option>
<option value="redux">Redux</option>
<option value="hooks">Hooks</option>
</select>
</form>
<button type="button" onClick={handleResetClick}>
Reset
</button>
<button type="button" onClick={handleHooksClick}>
Hooks!
</button>
</>
);
}
使用文件输入
最后,我们来谈谈文件输入框。这个特殊的输入框无法控制,但仍然可以获取一些数据并将其保存在状态中,以便在其他地方显示。在下面的示例中,我们为隐藏的文件输入框创建了一个自定义 UI。
function Form() {
const [fileKey, setFileKey] = React.useState(Date.now());
const [fileName, setFileName] = React.useState("");
const [fileSize, setFileSize] = React.useState(0);
const [error, setError] = React.useState(null);
function resetFile() {
setFileKey(Date.now());
setFileName("");
setFileSize(0);
setError(null);
}
function handleChange(event) {
const file = event.target.files[0];
setFileSize(file.size);
if (file.size > 100000) setError("That file is too big!");
else setError(null);
setFileName(file.name);
}
return (
<form>
<label htmlFor="file">
Select a single file to upload. (max size: 100kb)
<br />
{fileName && (
<>
<strong>File:</strong> {fileName} ({fileSize / 1000}kb)
</>
)}
<input id="file" type="file" key={fileKey} onChange={handleChange} style={{ display: "none" }} />
</label>
{error && (
<label style={{ color: "red" }} htmlFor="file">
{error}
</label>
)}
<button type="button" onClick={resetFile}>
Reset file
</button>
</form>
);
}
我们监听变化事件并读取文件大小和名称并验证文件的大小,如果文件太大,我们将状态设置error
为消息"That file is too big!"
,如果文件不是那么大,我们将错误设置为null
,如果用户之前选择了一个大文件,这让我们删除之前的错误。
我们还有一个按钮来重置输入,因为我们无法控制状态,所以我们可以使用key
强制 React 再次渲染输入并在过程中重置它,我们使用当前日期,每次用户单击Reset file
它时都会获取当前日期并将其保存到fileKey
状态并重置输入。