反应条件渲染
[英] React conditionally rendering
本文介绍了反应条件渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我从 React 构建了一个简单的表单.提交后,如果错误再次出现,我希望渲染一个额外的 div 以在表单上显示错误.
现在我让它工作了,但我不喜欢这个解决方案.我的解决方案是基于这样的知识:如果渲染函数内部的状态发生变化,组件只会重新渲染(在这种情况下是 this.state.errorMessages).所以我必须像这样明确地把 if 条件放在渲染函数中
renderError() {var errArr = [];for (var key in this.state.errorMessages) {errArr = [...errArr, ...this.state.errorMessages[key]];}返回 (<div className="alert alert-danger">{errArr.map((err) => {返回<p>{错误}</p>})}
)}呈现形式(){返回 (<form onSubmit={this.handleRegisterFormSubmit}><div className="form-group"><label>名字</label><input type="text" className="form-control" name="name" placeholder="Name" value={this.state.firstName} onChange={this.handleFirstNameChange} required/>
<div className="form-group"><label>姓氏</label><input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleLastNameChange} required/>
<div className="form-group"><label>电子邮件地址</label><input type="email" className="form-control" id="exampleInputEmail1" aria-writtenby="emailHelp" placeholder="Enter email" value={this.state.email} onChange={this.handleEmailChange}/><small id="emailHelp" className="form-text text-muted">我们绝不会与任何其他人分享您的电子邮件.</small>
<div className="form-group"><label>密码</label><input type="password" className="form-control" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
<div className="form-group"><label>密码确认</label><input type="password" className="form-control" name="password_confirmation" placeholder="密码确认" value={this.state.passwordConfirmation} onChange={this.handlePasswordConfirmationChange}/>
<div><button type="submit" className="btn btn-primary">提交</button><button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>取消</button>
</表单>)}使成为 () {如果(!this.state.errorMessages){返回 (<div>{this.renderForm()}
)} 别的 {返回 (<div>{this.renderForm()}{this.renderError()}
)}}
我真的不喜欢这种方法,因为如果我有更多条件要重新渲染,这可能会变得很糟糕.我希望有一个解决方案,即在实际渲染函数中没有太多逻辑并将其提取出来.例如...
renderError() {如果(!this.state.errorMessages){返回;}var errArr = [];for (var key in this.state.errorMessages) {errArr = [...errArr, ...this.state.errorMessages[key]];}返回 (<div className="alert alert-danger">{errArr.map((err) => {返回<p>{错误}</p>})})}使成为 () {<form onSubmit={this.handleRegisterFormSubmit}><div className="form-group"><label>名字</label><input type="text" className="form-control" name="name" placeholder="Name" value={this.state.firstName} onChange={this.handleFirstNameChange} required/>
<div className="form-group"><label>姓氏</label><input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleLastNameChange} required/>
<div className="form-group"><label>电子邮件地址</label><input type="email" className="form-control" id="exampleInputEmail1" aria-writtenby="emailHelp" placeholder="Enter email" value={this.state.email} onChange={this.handleEmailChange}/><small id="emailHelp" className="form-text text-muted">我们绝不会与任何其他人分享您的电子邮件.</small>
<div className="form-group"><label>密码</label><input type="password" className="form-control" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
<div className="form-group"><label>密码确认</label><input type="password" className="form-control" name="password_confirmation" placeholder="密码确认" value={this.state.passwordConfirmation} onChange={this.handlePasswordConfirmationChange}/>
<div><button type="submit" className="btn btn-primary">提交</button><button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>取消</button>
{this.renderError}</表单>}
这会抛出一个错误,因为它抱怨 this.renderError 应该作为函数调用.但是当我把它作为this.renderError()该错误永远不会呈现,因为它不会在错误返回时自动调用.
-----------更新-----------
或者,为什么我不能做类似下面的事情
render() {<div><form onSubmit={this.handleRegisterFormSubmit}>...</表单>{if (this.state.errorMessages) {this.renderError()}}}
这会引发控制台错误
<块引用>未捕获的错误:模块构建失败:语法错误:意外的令牌(117:13)
-----------更新2-----------
本质上,我正在寻找一种解决方案,即在渲染函数内部,当状态发生变化时,我可以轻松地显示整个代码块.在 Vue 中,我可以做类似的事情
解决方案
你可以只使用 map 来从你的对象中提取错误信息.
下面是 React 中表单验证和错误的最小示例.了解它的工作原理很好,但就我而言,我使用 Formik 简化了这个过程.
class Test 扩展 React.Component {构造函数(道具){超级(道具);this.state = { errorMessages: {} };}handleRegisterFormSubmit = e =>{e.preventDefault();//在我们运行下面的内容之前不要提交表单让错误消息 = {};if (!this.state.lastName) errorMessages.lastName = '您需要输入您的姓氏';//对每个字段验证依此类推//我们有错误吗?if (Object.keys(errorMessages).length > 0) {this.setState(errorMessages);} 别的 {//提交给服务器}};handleChange = e =>{this.setState({[e.target.name]: e.target.value,错误消息:{...this.state.errorMessages,[e.target.name]: null//如果正在编辑,则删除此字段的错误}});};使成为() {const errArr = Object.keys(this.state.errorMessages).map(key => this.state.errorMessages[key]);返回 (<form onSubmit={this.handleRegisterFormSubmit}><div className="form-group"><label>姓氏</label><input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleChange}/>{/* ... 你的 dom */}<div><button type="submit" className="btn btn-primary">提交按钮><button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>取消按钮>
{errArr.length >0 &&(<div className="alert alert-danger">{errArr.map(err => {返回 <p>{err}</p>;})}
)}</表单>);}}
另一种不显示警报 div 的方法是为 className 使用三元运算符并使用引导程序的 d-none
{errArr.map(err => {返回 <p>{err}</p>;})}
I have a simple form build from React. Upon submission, if the error comes back, I wish to render an extra div to show error on the form.
Right now I got it to work but I do not like the solution. My solution is based on the knowledge that the component will only re-render if the state changes inside the render function (In this case this.state.errorMessages). So I had to explicitly put the if condition inside the render function like so
renderError() {
var errArr = [];
for (var key in this.state.errorMessages) {
errArr = [...errArr, ...this.state.errorMessages[key]];
}
return (
<div className="alert alert-danger">
{errArr.map((err) => {
return <p>{err}</p>
})}
</div>
)
}
renderForm() {
return (
<form onSubmit={this.handleRegisterFormSubmit}>
<div className="form-group">
<label>First Name</label>
<input type="text" className="form-control" name="name" placeholder="Name" value={this.state.firstName} onChange={this.handleFirstNameChange} required/>
</div>
<div className="form-group">
<label>Last Name</label>
<input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleLastNameChange} required/>
</div>
<div className="form-group">
<label>Email address</label>
<input type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email" value={this.state.email} onChange={this.handleEmailChange} />
<small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
</div>
<div className="form-group">
<label>Password Confirmation</label>
<input type="password" className="form-control" name="password_confirmation" placeholder="Password Confirmation" value={this.state.passwordConfirmation} onChange={this.handlePasswordConfirmationChange}/>
</div>
<div>
<button type="submit" className="btn btn-primary">Submit</button>
<button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>Cancel</button>
</div>
</form>
)
}
render () {
if (!this.state.errorMessages) {
return (
<div>
{this.renderForm()}
</div>
)
} else {
return (
<div>
{this.renderForm()}
{this.renderError()}
</div>
)
}
}
I don't really like this approach as this could get nasty if I have more condition to re-render. I'm hoping there is a solution along the line of not having much logic in the actual render function and have that extracted out. For example...
renderError() {
if (!this.state.errorMessages) {
return;
}
var errArr = [];
for (var key in this.state.errorMessages) {
errArr = [...errArr, ...this.state.errorMessages[key]];
}
return (
<div className="alert alert-danger">
{errArr.map((err) => {
return <p>{err}</p>
})}
</div>
)
}
render () {
<form onSubmit={this.handleRegisterFormSubmit}>
<div className="form-group">
<label>First Name</label>
<input type="text" className="form-control" name="name" placeholder="Name" value={this.state.firstName} onChange={this.handleFirstNameChange} required/>
</div>
<div className="form-group">
<label>Last Name</label>
<input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleLastNameChange} required/>
</div>
<div className="form-group">
<label>Email address</label>
<input type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email" value={this.state.email} onChange={this.handleEmailChange} />
<small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
</div>
<div className="form-group">
<label>Password Confirmation</label>
<input type="password" className="form-control" name="password_confirmation" placeholder="Password Confirmation" value={this.state.passwordConfirmation} onChange={this.handlePasswordConfirmationChange}/>
</div>
<div>
<button type="submit" className="btn btn-primary">Submit</button>
<button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>Cancel</button>
</div>
{this.renderError}
</form>
}
This throws an error because it complains that this.renderError should be called as a function. But when I put it as
this.renderError()
The error will never render because it does not get automatically called when errors come back.
-----------Update----------
Alternatively, why can't I do something like the following
render () {
<div>
<form onSubmit={this.handleRegisterFormSubmit}>
...
</form>
{if (this.state.errorMessages) {this.renderError()}}
</div>
}
This throws console error
Uncaught Error: Module build failed: SyntaxError: Unexpected token
(117:13)
----------Update 2-----------
Essentially, I'm looking for a solution where inside the render function, I can easily show a whole block of code when the state changes. In Vue, I can do something like
<form>
<input type="text">
</form>
<div v-if="hasError">
<div class="alert alert-danger">{{something}}</div>
</div>
Can I do something as easy as this in React?
解决方案
You can just use map in order to extract the error message from your object.
Here below a minimal example of form validations and errors in React. It's good to understand how it works, but for my part, I use Formik which simplifies this process.
class Test extends React.Component {
constructor(props) {
super(props);
this.state = { errorMessages: {} };
}
handleRegisterFormSubmit = e => {
e.preventDefault(); // don't submit the form until we run what's below
let errorMessages = {};
if (!this.state.lastName) errorMessages.lastName = 'You need to enter your last name';
// And so on for each field validation
// Do we have errors ?
if (Object.keys(errorMessages).length > 0) {
this.setState(errorMessages);
} else {
// Submit to server
}
};
handleChange = e => {
this.setState({
[e.target.name]: e.target.value,
errorMessages: {
...this.state.errorMessages,
[e.target.name]: null // remove the error of this field if it's being edited
}
});
};
render() {
const errArr = Object.keys(this.state.errorMessages).map(key => this.state.errorMessages[key]);
return (
<form onSubmit={this.handleRegisterFormSubmit}>
<div className="form-group">
<label>Last Name</label>
<input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleChange} />
</div>
{/* ... your dom */}
<div>
<button type="submit" className="btn btn-primary">
Submit
</button>
<button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>
Cancel
</button>
</div>
{errArr.length > 0 && (
<div className="alert alert-danger">
{errArr.map(err => {
return <p>{err}</p>;
})}
</div>
)}
</form>
);
}
}
One more way to not display your alert div is with a ternary operator for your className and using bootstrap's d-none
<div className={errArr.length ? "alert alert-danger" : "d-none"}>
{errArr.map(err => {
return <p>{err}</p>;
})}
</div>
这篇关于反应条件渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文