簡體   English   中英

如何避免以反應形式添加現場更換處理方法和其他樣板?

[英]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 }.

為了避免為反應組件中的方法編寫手動綁定,您可以遵循以下兩種方法 -

  1. 使用es6箭頭功能
  2. 一個黑客(我不知道這種方法是快還是慢但它有效:))

在組件中創建這樣的方法。

_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.
    );


}

編輯:

添加驗證 -

  1. 編寫一個可以迭代狀態鍵並檢查狀態是否為空的方法。
  2. 如果任何輸入字段為空,請收集有關該輸入的詳細信息並標記所需。
  3. 設置一個狀態以指示表單有錯誤。 可以在狀態的錯誤對象中找到特定的錯誤詳細信息。

     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 isEmptyisEmptyObj 它們只檢查對象是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處理程序,用於整個表單
  • per-field(例如onBlur )和form(例如onSubmit )驗證
  • 普通對象和不可變狀態助手
  • 與Redux或任何其他狀態管理解決方案輕松集成

它在內部使用context ,非常小,模塊化的源代碼很容易遵循。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM