score:28

Accepted answer

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.

score:0

The problem is common happen when you have a complex page, that need re-render always that you update the state. So you can percept that is very slow when typing.

I found a solution: The cycle of life of react run by component. So you can create other component and manage yours events, like onChange, after you can call onBlur, that is passed by props for him. It worked for me:

import React, {Fragment, useState, useEffect} from 'react';
import TextField from '@material-ui/core/TextField';


export function InputText(props) {
  const [value, setValue] = useState("");
  const {onBlur = (e) => {console.log(e)}, name='name', defaultValue= 'Default', type='text', label='Label'} = props

  useEffect(() => {

    // console.log(value);
  })

  return (
      <label>
        <TextField 
          name={name} 
          label={label}  
          onBlur={e => onBlur(e)}
          type={type}
          value={value}
          onChange={e => setValue(e.target.value)}
        />
      </label>
  );
}


class Sample extends React.Component {
    handleBlurInput = e => {        
         this.setState({ [e.target.name]: e.target.value });
    };
  render() {
    return (
    <InputText name="nome" label="Label Sample" defaultValue={this.state.nome} onBlur={this.handleBlurInput.bind(this)} />

    // Complex app ....
    );
  }
}

score:1

Use onChangeText instead

import { TextInput, View} from "react-native";  
import { connect } from "react-redux"; 
import React, { Component, useState } from "react";

function SearchTextInput(props) {
  const { keyword = "", setKeyword } = props; 
  return (
     <TextInput
       style={styles.searchInputText}
       placeholder={"placeholder here"}
       value={keyword}
       onChangeText={setKeyword(t)}
     />
  );
}

const mapStateToProps = state => {
  return {
    keyword: state.search.keyword,
    search: state.search
  };
};
const mapDispatchToProps = dispatch => ({
  setKeyword: payload => dispatch(({type:'updateSearchText', keyword: payload }))
});
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(SearchTextInput);

score:3

The answer is not to re-render your component on every key stroke, only if user stops typing in. Something like this:

shouldComponentUpdate(nextProps, nextState) {
    if (!textInputReRender)
        return false;
    else
        return true;
}

onTextInputChange = (propName, propValue) => {
    if (inputChangeTimerId)
        clearTimeout(inputChangeTimerId);

    inputChangeTimerId = setTimeout(() => {
        inputChangeTimerId = null;
        const newState = {};

        textInputReRender = true;

        newState[propName] = propValue;
        this.setState(newState);
    }, 500);

    textInputReRender = false;
}

score:4

The issue here is possibly re-renders. You're passing in "settings" (your entire state) to your component containing the "input", and we don't know how the rest of your connected components are coupled to state. Check to see if as a result of the state object mutating, you're rerendering much more than just the input on every keystroke. The solution to this is to more directly pass in the specific parts of state you need from mapStateToProps (in this case, maybe only pass in "flashVarsValue" if that's all this component needs, and make sure other components aren't also passed the whole state) and use PureRenderMixin or Dan Abramov's https://github.com/gaearon/react-pure-render if you're using ES6 components to not re-render if your props haven't changed

score:5

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.

score:5

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

Related Query

More Query from same tag