javascript - 验证 render() 中使用的状态中的变量以设置样式/填充 html
问题描述
我有以下 React 组件,它包含一个带有两个输入和一个按钮的表单。
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: null,
password: null
}
}
emailInputChanged = (e) => {
this.setState({
email: e.target.value.trim()
});
};
passwordInputChanged = (e) => {
this.setState({
password: e.target.value.trim()
});
};
loginButtonClicked = (e) => {
e.preventDefault();
if (!this.isFormValid()) {
//Perform some API request to validate data
}
};
signupButtonClicked = (e) => {
e.preventDefault();
this.props.history.push('/signup');
};
forgotPasswordButtonClicked = (e) => {
e.preventDefault();
this.props.history.push('/forgot-password');
};
isFormValid = () => {
const {email, password} = this.state;
if (email === null || password === null) {
return false;
}
return isValidEmail(email) && password.length > 0;
};
render() {
const {email, password} = this.state;
return (
<div id="login">
<h1 className="title">Login</h1>
<form action="">
<div className={(!isValidEmail(email) ? 'has-error' : '') + ' input-holder'}>
<Label htmlFor={'loginEmail'} hidden={email !== null && email.length > 0}>email</Label>
<input type="text" className="input" id="loginEmail" value={email !== null ? email : ''}
onChange={this.emailInputChanged}/>
</div>
<div className={(password !== null && password.length === 0 ? 'has-error' : '') + ' input-holder'}>
<Label htmlFor={'loginPassword'}
hidden={password !== null && password.length > 0}>password</Label>
<input type="password" className="input" id="loginPassword"
value={password !== null ? password : ''}
onChange={this.passwordInputChanged}/>
</div>
<button type="submit" className="btn btn-default" id="loginButton"
onClick={this.loginButtonClicked}>
login
</button>
</form>
<div className="utilities">
<a href={'/signup'} onClick={this.signupButtonClicked}>don't have an account?</a>
<a href={'/forgot-password'} onClick={this.forgotPasswordButtonClicked}>forgot your password?</a>
</div>
</div>
)
}
}
export function isValidEmail(email) {
const expression = /\S+@\S+/;
return expression.test(String(email).toLowerCase());
}
输入的值存储在组件的state
. 我已经给了它们初始值并在事件中null
使用更新它们。setState()
onChange
在该render()
方法中,我使用状态为具有无效值的输入着色。目前,我仅根据简单的正则表达式检查电子邮件值,并且密码长度至少为 1 个字符。
我将状态变量的初始值设置为的原因是,null
我可以检查布局和输入上的初始样式以不标记为"has-errors"
. 但是我需要将检查扩展到:
this.state.email !== null && this.state.email.length === 0
为了工作,因为 null 没有length
属性。
是否有更清洁和“React-ish”的方式来实现这一点: - 保存输入的 div 的初始状态没有类has-errors
- 在输入上设置属性时检查较少value
(因为 React 不接受null
作为属性的值)
编辑:
this.state.email
如果and
的初始值this.state.password
是空字符串,我将has-error
应用于保存输入的 div。在我看来,这是糟糕的用户体验,因为用户没有做任何事情而且他已经错了。
该hidden
属性由我制作的自定义组件使用,它的作用类似于“占位符”(如果在输入中键入内容,则会被删除)。
下面的视频显示了我的表单在何时为空字符串时的样子this.state.email
以及this.state.password
我的<Label>
组件如何工作:
解决方案
您可以创建一个验证函数,该函数返回一个错误对象以了解哪些字段出错,并使用空字符串作为初始值。我不明白你想用 hidden 属性做什么。
编辑:在状态中添加一个touched属性,以知道哪个字段被触动了。
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
touched: {},
};
}
emailInputChanged = e => {
this.setState({
email: e.target.value.trim(),
touched: {
...this.state.touched,
email: true,
},
});
};
passwordInputChanged = e => {
this.setState({
password: e.target.value.trim(),
touched: {
...this.state.touched,
password: true,
},
});
};
loginButtonClicked = e => {
e.preventDefault();
if (!this.isFormValid()) {
//Perform some API request to validate data
}
};
isFormValid = () => {
const errors = this.validate();
return Object.keys(errors).length === 0;
};
validate = () => {
const errors = {};
const { email, password } = this.state;
if (!isValidEmail(email)) {
errors.email = true;
}
if (password.length === 0) {
errors.password = true;
}
return errors;
};
render() {
const { email, password, touched } = this.state;
const errors = this.validate();
return (
<div id="login">
<h1 className="title">Login</h1>
<form action="">
<div
className={
(errors.email && touched.email ? 'has-error' : '') +
' input-holder'
}
>
<Label htmlFor={'loginEmail'}>email</Label>
<input
type="text"
className="input"
id="loginEmail"
value={email}
onChange={this.emailInputChanged}
/>
</div>
<div
className={
(errors.password && touched.password ? 'has-error' : '') +
' input-holder'
}
>
<Label htmlFor={'loginPassword'}>password</Label>
<input
type="password"
className="input"
id="loginPassword"
value={password}
onChange={this.passwordInputChanged}
/>
</div>
<button
type="submit"
className="btn btn-default"
id="loginButton"
onClick={this.loginButtonClicked}
>
login
</button>
</form>
</div>
);
}
}
export function isValidEmail(email) {
const expression = /\S+@\S+/;
return expression.test(String(email).toLowerCase());
}
推荐阅读
- r - 我如何在 R 中可视化价格、年份、状态、产品类型和地区?
- ruby-on-rails - 如何使用集合选择为嵌套属性设置表单?
- python - Python - 为什么多线程不能提高我的代码速度?
- sails.js - Sails - Waterline:在哪里可以找到模型属性的完整列表?
- javascript - 来自 webbrowser 中远程控制的事件
- mysql - 创建 TRIGGER 后插入值的问题
- sql - 对postgres数据库索引机制的质疑
- json - Swift Codable - 如何编码和解码字符串化的 JSON 值?
- javascript - 比较两个数组并在未找到项目时创建另一个数组
- haskell - Traversable 和 MonoTraversable 之间有什么区别吗?