How to avoid adding field change processing methods and other reaction form templates?

I have a reactive form with more than 10 fields, I have states for those ten formfields (controlled component) .

Most of these fields inputare of type text, but fields of other types will be added later.

The problem is that I need to write 10 change handlers so that they set the state correctly and then add method bindings for each of them in the constructor.

I am completely new to respond and may not know the correctness of methodologies and methods.

Please help me improve my current code structure and avoid writing boiler tables and repeated error code.

My current registration component is similar to below -

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;
    }
}
+4
source share
3 answers

There may be other ways to do this that I do not know about.

But I prefer to do change processing in a generic method for a certain type of generic fields, such as <input type of text />

This is an example input field -

  <input
      onChange    = {this.onChange}
      value       = {this.state.firstName}
      type        = "text"
      name        = {"firstName"}
  />

I save the name of the status field and the name "name" . After that I write a general change handler for all such fields.

You need to write only one line in the change handler.

onChange(e) {
    this.setState({[e.target.name]: e.target.value});
}

I am using es6 dynamic property parameter from string as property name

{ ["propName] : propValue }.

, -

  • es6
  • ( , , :))

.

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


}

EDIT:

-

  • , , .
  • - , .
  • , , . .

    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. , undefined, .

, .

+5

, . 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)

context, , , .

, , , 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}
      />
    )
  }
}
+2

, NeoForm:

  • onChange
  • (, onBlur) (, onSubmit)
  • Redux

context , .

0
source

Source: https://habr.com/ru/post/1680731/


All Articles