受控组件与非受控组件
大约 2 分钟
受控组件与非受控组件
受控组件
表单数据交由state对象管理, 受控表单往往给予了我们更大的选择,例如比较复杂的、非 HTML 标准的表单校验,如检查密码强度和对用户手机号进行格式化。
特点:可以实时得到表单数据,代码相对复杂
import React, { useState } from 'react'
function ControlledForm() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = () => {
sendInputValueToApi(value).then(() => /** 业务逻辑... */);
};
return (
<>
<input type="text" value={value} onChange={handleChange} />
<button onClick={handleSubmit}>send</button>
</>
)
}
因为数据已经保存在 state 中,所以我们并不需要真正的 onSubmit 事件,而且在按钮点击时,我们也并不需要直接访问 input 的值。
受控缺点
你可能不想要每次用户输入时都去重新渲染组件。
你需要写许多代码去管理复杂的表单,因为随着表单规模的增长,会导致出现大量的 state 和 setSate,从而使代码变的非常臃肿。
构建动态表单将变的非常困难,因为你无法在条件判断中使用像 useState 的 hooks。
整个表单的值将存储在一个巨大的对象中,然而这会导致所有的子组件将在任一其他组件变化时全部重新渲染,因为我们更新的方式是
setState({ ...preState, field: newValue })
。在大型表单例如表格和 Excel 中,这会导致性能问题。
非受控组件
非受控表单使用原生 HTML 内置的 <form>
的功能和 JavaScript 去管理数据。
举例来说,浏览器会帮我们管理状态,我们无需在每次 input 改变时使用 setState 更新 state 并把 state 设置到 input 的 value 属性上,我们的组件不再需要或使用这些 state
特点:表单数据在需要时进行获取,代码实现相对简单。
function UncontrolledForm() {
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const inputValue = formData.get('inputName');
sendInputValueToApi(inputValue).then(() => /* 业务逻辑... */)
};
return (
<form onSubmit={handleSubmit}>
<input type="text" name="inputName" />
<button type="submit">Send</button>
</form>
);
}
混合使用
将受控 input 抽离出来以此来减少重新渲染对表单其余部分的影响。
const PhoneInput = () => {
const [phoneNumber, setPhoneNumber] = useState("");
const handlePhoneNumberChange = (event) => {
const formattedNumber = formatPhoneNumber(event.target.value);
setPhoneNumber(formattedNumber);
};
return (
<input
type="tel"
name="phoneNumber"
value={phoneNumber}
onChange={handlePhoneNumberChange}
/>
);
};
function MixedForm() {
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData(event.target);
for (let [key, value] of formData.entries()) {
console.log(`${key}: ${value}`);
}
};
return (
<form onSubmit={handleSubmit}>
<label>Name:</label>
<input type="text" name="name" />
<label>Email:</label>
<input type="email" name="email" />
<label>Phone Number:</label>
<PhoneInput />
<label>Address:</label>
<input type="text" name="address" />
<button type="submit">Submit</button>
</form>
);
}
function formatPhoneNumber(number) {
return number.replace(/\D/g, "").slice(0, 10);
}
选用标准
大多数情况下,推荐受控组件处理表单,除非表单交互比较简单