javascriptreactjs

React slow with multiple controlled text inputs


I have a form with multiple text inputs. I have them all set up as controlled inputs. When typing, there is a lag of up to several seconds for the new text to display in the field. Here is an example field:

<label>Event Name</label>
<input type="text" 
       placeholder="Title"
       className="form-control"
       name="title"
       value={this.state.event.title}
       onChange={this.handleChange} />

I can't figure out what's causing it to be so slow or what to do to fix it.

UPDATED: Here's the component, should be enough to show what's going on.

let CreateEventForm = React.createClass({
  submit: function () {},
  handleChange: function(e){
    let value = e.target.value;
    let name = e.target.name;
    if(value === 'true'){
      value = true;
    }
    if(value === 'false'){
      value = false;
    }
    // If true/false toggle old
    let oldState = this.state.event[name];
    if(typeof oldState === 'boolean'){
      value = !oldState;
    }
    // If is array
    if(name.indexOf('[]') > -1){
      name = name.replace('[]', '');
      oldState = this.state.event[name];
      var pos = oldState.indexOf(value);
      if(pos > -1){
        oldState.splice(pos, 1);
      } else {
        oldState.push(value);
      }
      value = oldState;
    }
    let event = this.state.event;
    event[name] = value;
    this.setState({event: event});
    console.log(this.state.event);
  },
  getClasses(field, additionalClasses = []) {
    // If a string is passed for additional class, make array
    if(!Array.isArray(additionalClasses)){
      additionalClasses = [additionalClasses];
    }
    let useDefaultColumns = additionalClasses.filter(function(className){
        return className.indexOf('col-') > -1;
      }).length === 0;
    let hasError = function(){
      let fields = Array.isArray(field) ? field : [field];
      return fields.filter(function(field){
          return !this.props.isValid(field);
        }.bind(this)).length > 0;
    }.bind(this)();
    return classnames({
      'col-sm-4': useDefaultColumns,
      'form-group': true,
      'has-error': hasError
    }, additionalClasses);
  },
  render: function () {
    return (
      <form ref="eventForm" onSubmit={this.submit}>
        <SavedModal isOpen={this.state.saved} reset={this.resetForm} style={this.state.modals.styles} />
        <h3>Info</h3>

        <div className="row">
          <div className={this.getClasses('title')}>
            <label>Event Name</label>
            <input type="text" placeholder="Title"
                   className="form-control"
                   name="title"
                   value={this.state.event.title}
                   onChange={this.handleChange} />
            {this.renderHelpText(this.props.getValidationMessages('title'))}
          </div>
        </div>
        <div className="row">
          <div className={this.getClasses('type')}>
            <label>Event Type</label>
            <select name="type"
                    className="form-control"
                    value={this.state.event.type}
                    onChange={this.handleChange}
                    onBlur={this.props.handleValidation('type')}>
              <option value="">Select Event Type&hellip;</option>
              {this.state.calendarTypes.map(function (type, key) {
                return <option value={type.name} key={key}>{type.name}</option>
              })}
            </select>
            {this.renderHelpText(this.props.getValidationMessages('type'))}
          </div>
        </div>

        <h3>Duration</h3>

        <div className="row">
          <div className="form-group col-sm-2">
            <input type="checkbox" name="allDay" checked={this.state.event.allDay} onChange={this.handleChange}/> All Day
          </div>
        </div>
        <div className="row">
          <div className="form-group col-sm-2">
            <input type="checkbox" name="repeats" checked={this.state.event.repeats} onChange={this.handleChange}/> Repeats&hellip;
          </div>
          <br/><br/>
        </div>

        <h3>Location</h3>
        <div className="row">
          <div className={this.getClasses('location')}>
            <select name="location"
                    className="form-control"
                    value={this.state.event.location}
                    onBlur={this.props.handleValidation('location')}
                    onChange={this.handleChange}>
              <option value="">Select a Location&hellip;</option>
              {this.state.locations.map(function (location, key) {
                return (
                  <option value={location.name} key={key}>{location.name}</option>
                );
              })}
            </select>
            {this.renderHelpText(this.props.getValidationMessages('location'))}
          </div>
        </div>

        <h3>Description</h3>
        <div className="row">
          <div className={this.getClasses('description')}>
            <label>Write a description:</label>
            <textarea className="form-control"
                      name="description"
                      value={this.state.event.description}
                      onChange={this.handleChange}
                      onBlur={this.props.handleValidation('description')}
                      rows="10"></textarea>
            {this.renderHelpText(this.props.getValidationMessages('description'))}
          </div>
        </div>

        <h3>Event Details</h3>
        <div className="row">
          <div className={this.getClasses('fee')}>
            <label>Fee:</label>
            <input type="text"
                   className="form-control"
                   name="fee"
                   value={this.state.event.fee}
                   onChange={this.handleChange}
                   onBlur={this.props.handleValidation('fee')}/>
            {this.renderHelpText(this.props.getValidationMessages('fee'))}
          </div>
        </div>

        <div className="row">
          <div className="col-sm-12">
            <button className="btn btn-primary" type="submit">
              Create Event
            </button>
          </div>
        </div>

      </form>
    );
  }
});

Solution

  • Seeing as this still gets responses, thought I'd update this and close it. Calling handleChange within onChange would cause the entire form to rerender on every change, thereby slowing it down. If you had a simple form you could just update onBlur instead or create individual input components so the rerender would be isolated to that one input. Personally, I use and would recommend using Formik for building forms as it abstracts this complexity for you.