[英]How to avoid adding field change handling methods and other boilerplates in react form?
我有在它超過10個字段一個反應基的形式,我對這些十個州 form
字段(控制部件)。
這些input
字段中的大多數僅為text
類型,但稍后將添加其他類型字段。
問題是我需要為它們編寫10個更改處理程序以正確設置狀態,然后在構造函數中為每個處理程序添加方法綁定。
我很反應,可能不了解正確的方法和技術。
請指導我如何改進我當前的代碼結構,避免編寫樣板和重復的錯誤代碼。
我目前的注冊組件如下 -
export default class Register extends Component {
constructor(props){
super(props);
this.state = {
regName : '',
regAdd1 : '',
regAdd2 : '',
regState : '',
regZipCode : '',
regCity : '',
regPhone : ''
};
// add bindings .... ugh..
this.changeRegAdd1 = this.changeRegAdd1.bind(this);
this.changeRegAdd2 = this.changeRegAdd2.bind(this);
//Similary binding for other handlers...
}
// add individual field change handlers ... ugh...
changeRegName(e) {
this.setState({regName:e.target.value});
}
changeRegAdd1(e) {
this.setState({regAdd1:e.target.value});
}
changeRegAdd2(e) {
this.setState({regAdd2:e.target.value});
}
changeRegState(e) {
this.setState({regState:e.target.value});
}
// Similary for other change handler ....
handleSubmit(e) {
e.preventDefault();
// validate then do other stuff
}
render(){
let registrationComp = (
<div className="row">
<div className="col-md-12">
<h3>Registration Form</h3>
<fieldset>
<div className="form-group">
<div className="col-xs-12">
<label htmlFor="regName">Name</label>
<input type="text" placeholder="Name"
onChange={this.changeregName} value = {this.state.regName} className="form-control" required autofocus/>
</div>
</div>
<div className="form-group">
<div className="col-xs-12">
<label htmlFor="regAdd1">Address Line1</label>
<input
type = "text"
placeholder = "Address Line1"
onChange = {this.changeregAdd1}
value = {this.state.regAdd1}
className = "form-control"
required
autofocus
/>
<input
type = "text"
placeholder = "Address Line2"
onChange = {this.changeregAdd2}
value = {this.state.regAdd2}
className = "form-control"
required
autofocus
/>
</div>
</div>
<div className="form-group">
<div className="col-xs-6">
<label htmlFor="regState">State</label>
<input
type = "text"
placeholder = "State"
onChange = {this.changeregState}
value = {this.state.regState}
className = "form-control"
required
autofocus
/>
</div>
<div className="col-xs-6">
<label htmlFor="regZipCode">Zip Code</label>
<input
type = "text"
placeholder = "Zip Code"
onChange = {this.changeregZipCode}
value = {this.state.regZipCode}
className = "form-control"
required
autofocus
/>
</div>
</div>
<div className="form-group">
<div className="col-xs-12">
<label htmlFor="regCity">City</label>
<input
type = "text"
placeholder = "City"
title = "City"
onChange = {this.changeregCity}
value = {this.state.regCity}
className = "form-control"
required
autofocus
/>
</div>
</div>
{/* other form fields */}
</fieldset>
</div>
</div>
);
return registrationComp;
}
}
可能有其他很多方法可以做到,我可能不知道。
但我更喜歡在某種常見字段的常用方法中進行變更處理,例如<input type of text />
這是一個示例輸入字段 -
<input
onChange = {this.onChange}
value = {this.state.firstName}
type = "text"
name = {"firstName"}
/>
我保持狀態的字段名稱和輸入的“名稱”屬性相同。 之后,我為所有這些字段編寫了一個通用的更改處理程序 。
需要在變更處理程序中只寫一行。
onChange(e) {
this.setState({[e.target.name]: e.target.value});
}
我使用es6的動態屬性設置從字符串作為屬性名稱
{ ["propName] : propValue }.
為了避免為反應組件中的方法編寫手動綁定,您可以遵循以下兩種方法 -
在組件中創建這樣的方法。
_bind(...methods) {
methods.forEach( (method) => this[method] = this[method].bind(this) );
}
使用_bind
綁定您的方法。
constructor(props){
super(props);
this.state = {
regName : '',
regAdd1 : '',
regAdd2 : '',
regState : '',
regZipCode : '',
regCity : '',
regPhone : ''
};
// add bindings .... ugh..
//this.changeRegAdd1 = this.changeRegAdd1.bind(this);
//this.changeRegAdd2 = this.changeRegAdd2.bind(this);
//Similary binding for other handlers...
this._bind(
'changeRegName',
'changeReg1' , 'changeRegAdd2'
// and so on.
);
}
編輯:
添加驗證 -
設置一個狀態以指示表單有錯誤。 可以在狀態的錯誤對象中找到特定的錯誤詳細信息。
validateInput() { let errors = {}; Object.keys(this.state) .forEach((stateKey) => { isEmpty(this.state[stateKey]) ? (errors[stateKey] = `*required` ) : null; }); return { errors, isValid : isEmptyObj(errors) }; } isFormValid() { const { errors, isValid } = this.validateInput(); if (!isValid) { this.setState({ errors}); } return isValid; } onSubmit(e) { e.preventDefault(); this.setState({errors : {}}); if (this.isFormValid()) { // Perform form submission } }
我習慣了實用方法calld isEmpty
, isEmptyObj
。 它們只檢查對象是null還是未定義或field是否為空。
我希望這有幫助。
您可以創建一個更高階的組件來處理很多這樣的組件。 Redux Form有一個非常好的模式,你可以根據需要建模。
你基本上會得到類似下面的內容(我根本沒有測試過,但它應該可以正常工作):
export class Field extends Component {
handleChange = (event) => this.props.onChange(this.props.name, event.target.value)
render() {
const InputComponent = this.props.component
const value = this.props.value || ''
return (
<InputComponent
{...this.props}
onChange={this.handleChange}
value={value}
/>
}
}
export default function createForm(WrappedComponent) {
class Form extends Component {
constructor() {
super()
this.state = this.props.initialValues || {}
this.handleChange = this.handleChange.bind(this)
}
handleChange(name, value) {
this.setState({
[name]: value,
})
}
render() {
return (
<WrappedComponent
{...this.state}
{...this.props}
// pass anything you want to add here
onChange={this.handleChange}
values={this.state}
/>
)
}
}
return Form
}
然后,您可以根據需要增加此組件(添加焦點,模糊,提交處理程序等)。 你可以使用這樣的東西:
import createForm, { Field } from './createForm'
// simplified Registration component
export class Registration extends Component {
render() {
return (
<form>
<Field
component="input"
name="name"
onChange={this.props.onChange}
type="text"
value={this.props.values.name}
/>
</form>
)
}
}
export default createForm(Registration)
你可能會瘋狂並進入上下文,所以你不必手動傳遞值和函數,但我會保持至少,直到你更熟悉React。
此外,如果您不想手動綁定函數,則可以使用類屬性轉換(如果您使用的是babel)。 然后Form
組件將如下所示:
class Form extends Component {
state = this.props.initialValues || {}
handleChange = (name, value) => this.setState({
[name]: value,
})
render() {
return (
<WrappedComponent
{...this.state}
{...this.props}
onChange={this.handleChange}
values={this.state}
/>
)
}
}
看看它在NeoForm中是如何完成的:
onChange
處理程序,用於整個表單 onBlur
)和form(例如onSubmit
)驗證 它在內部使用context
,非常小,模塊化的源代碼很容易遵循。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.