表单组件
表单组件
受控组件与非受控组件
常用组件
Text
Select
表单验证
在我们真实的表单组件开发中,我们不可避免地需要对于用户输入的内容进行验证并且根据验证结果给予用户相关反馈提示。实际开发中,我们会使用受控组件,这样所有的表单数据都会存放于组件状态中(暂时不考虑状态存放于组件外),我们也可以很方便地根据内部状态进行计算。譬如产品需求是唯有用户在输入有效的邮箱地址时才允许点击注册按钮,否则注册按钮处于不可点击状态,图示如下:
我们可以使用简单的表达式来推导是否应该允许点击按钮,即仅当邮箱长度大于 0 并且密码长度大于 0 的时候才允许点击。
const { email, password } = this.state;
const isEnabled = email.length > 0 && password.length > 0;
<button disabled={!isEnabled}>Sign up</button>;
到这里我们已经完成了最简单基础的表单验证,不过在真实工程开发中我们会遇到的最头痛的问题反而不是验证本身,而在于如何进行合适的错误反馈。常见的输入框错误反馈模式有如下几种:
不同的产品经理、不同的产品对于这些错误反馈有不同的喜好,不过从工程的角度上我们希望尽可能地将逻辑与界面表示相分离,并且能够根据产品经理的要求迅速改变错误反馈模式与具体的样式。首先,我们需要考虑下组件内的存储错误信息的可独立于界面层的数据结构。基本的数据结构如下所示:
errors: {
name: false,
email: true,
}
这里的false
代表某个域是验证通过的,而true
则代表某个域是有问题的。在构建了存储错误信息的数据结构之后,我们要接着讲验证的过程独立于渲染函数以使其符合单一职责原则:
function validate(email, password) {
// true means invalid, so our conditions got reversed
return {
email: email.length === 0,
password: password.length === 0,
};
}
这里的validate
函数是典型的纯函数,我们可以方便地对其进行单元测试或者重构。下面我们需要在渲染函数中调用该验证函数:
const errors = validate(this.state.email, this.state.password);
在获取了错误信息后,我们还需要在按钮的属性上引用错误信息,完整的注册表单代码为:
class SignUpForm extends React.Component {
constructor() {
super();
this.state = {
email: '',
password: '',
touched: {
email: false,
password: false,
},
};
}
// ...
handleBlur = (field) => (evt) => {
this.setState({
touched: { ...this.state.touched, [field]: true },
});
}
render()
const shouldMarkError = (field) => {
const hasError = errors[field];
const shouldShow = this.state.touched[field];
return hasError ? shouldShow : false;
};}
// ...
/**
<input
className={shouldMarkError('email') ? "error" : ""}
onBlur={this.handleBlur('email')}
type="text"
placeholder="Enter email"
value={this.state.email}
onChange={this.handleEmailChange}
/>
*/
}