Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React + Redux - Input onChange is very slow when typing in when the input have a value from the state

I got my input who is filled by a value from my state.

<input id="flashVars" name="flashVars" type="text" value={settings.flashVarsValue} disabled={isDisabled} onChange={handleChange} />

Settingsis my state with Redux. When i put a value into my input, i must specify a onChange function. This is my onChange function:

handleFlashVarsChange(e) {
  let { dispatch } = this.props;

  dispatch( changeFlashVarsValue(e.target.value) );
}

It change the state value flashVarsValue for the value of the input. But when i type in my input, it lags. I don't understand why i should call the dispatch each time i change the input value.

Is there any way who can give less lags?

My reducer:

import { ACTIONS } from '../utils/consts';

const initialState = {
  ...
  flashVarsValue: '',
  ...
};

export function formSettings(state = initialState, action = '') {
  switch (action.type) {

    ...

    case ACTIONS.CHANGE_FLASHVARS_VALUE:
      return Object.assign({}, state, {
        flashVarsValue: action.data
      });

    default:
      return state;
  }
}

My action:

export function changeFlashVarsValue(data) {
  return {
    type: ACTIONS.CHANGE_FLASHVARS_VALUE,
    data: data
  }
}

Thank you

like image 585
Mike Boutin Avatar asked Oct 21 '15 17:10

Mike Boutin


3 Answers

I had a similar problem when I was editing a grid with a million rows, so what I did was to change the update logic, in your case handleChange to be called only on the event onBlur instead of onChange. This will only trigger the update when you lose focus. But don't know if this would be a satisfactory solution for you.

like image 125
luanped Avatar answered Oct 13 '22 13:10

luanped


The answer for me was to use the shouldComponentUpdate lifecycle hook. This has already been given as an answer in a comment by Mike Boutin (about a year ago :) ), but an example might help the next visitor here.

I had a similar problem, with the text input being lost, and slow and jumpy. I was using setState to update the formData in my onChange event.

I found that the form was doing a complete re-render with every keypress, as the state had changed. So to stop this, I overrode the function:

shouldComponentUpdate(nextProps, nextState) {
   return this.state.formErrors !== nextState.formErrors);
}

I show an error notification panel on form submission with any new or changed validation errors, and that's the only time I need to re-render.

If you have no child components, you could probably just set the form component's shouldComponentUpdate to always return false.

like image 28
ben.tiberius.avery Avatar answered Oct 13 '22 11:10

ben.tiberius.avery


I know this is an old question, but if you want to fire onChange on a text input, you probably want to debounce your event. This thread does a good job breaking it down, but I think this would work for the op's example:

import debounce from 'debounce'                                      

function debounceEventHandler(...args) {
  const debounced = debounce(...args)
  return function (e) {
    e.persist();
    return debounced(e);
  }
}                                                                      
const Container = React.createClass({
  handleFlashVarsChange(e) {
    let { dispatch } = this.props;
    //basic redux stuff
    this.props.changeFlashVarsValue(e.target.value));
  },
  render() {
    const handleChange = debounceEventHandler(this.handleFlashVarsChange, 15);
    return (
      <input id="flashVars" onChange={handleChange} />
    )
  }                                                                         
}
//...prep and return your redux container
like image 5
Joe Avatar answered Oct 13 '22 12:10

Joe