avoid constant re-render from “input” or “textarea” in react js

前端 未结 4 1452
面向向阳花
面向向阳花 2021-01-11 14:32

Currently in react js, when I want to bind a text area or an input with a \"state\", I will need to set the onChange method and setState() everytime user type in a single le

相关标签:
4条回答
  • 2021-01-11 14:48

    You need to bind the onChange() event function inside constructor like as code snippets :

    class MyComponent extends Component {
      constructor() {
        super();
        this.state = {value: ""};
        this.onChange = this.onChange.bind(this)
      }
    
      onChange= (e)=>{
        const formthis = this;
        let {name, value} = e.target;
    
        formthis.setState({
          [name]: value
        });
      }
    
      render() {
        return (
          <div>
            <form>
                <input type="text" name="name" onChange={this.onChange}  />
                <input type="text" name="email" onChange={this.onChange}  />
                <input type="text" name="phone" onChange={this.onChange}  />
                <input type="submit" name="submit" value="Submit"  />
            </form>
          </div>
        );
      }
    }
    
    0 讨论(0)
  • 2021-01-11 14:48

    You don't need a complicated react solution to this problem, just a little common sense about when to update state. The best way to achieve this is to encapsulate your setState call within a timeout.

    class Element extends React.Component {
        onChange = (e) => {
            clearTimeout(this.setStateTimeout)
            this.setStateTimeout = setTimeout(()=> {
                this.setState({inputValue: e.target.value})
            }, 500)
        }
    }
    

    This will only set state on your react element a 500ms after the last keystroke and will prevent hammering the element with rerenders as your user is typing.

    0 讨论(0)
  • 2021-01-11 14:50

    Well, that's how you implement controlled input elements in React.

    However, if performance is a major concern of yours, you could either isolate your input element in a separate stateful component, hence only triggering a re-render on itself and not on your entire app.

    So something like:

    class App extends Component {    
      render() {
        return (
          <div>
            ...
            <MyInput />
            ...
          </div>
        );
      }
    }
    
    
    class MyInput extends Component {
      constructor() {
        super();
        this.state = {value: ""};
      }
    
      update = (e) => {
        this.setState({value: e.target.value});
      }
    
      render() {
        return (
          <input onChange={this.update} value={this.state.value} />
        );
      }
    }
    

    Alternatively, you could just use an uncontrolled input element. For example:

    class App extends Component {    
      render() {
        return (
          <div>
            ...
            <input defaultValue="" />
            ...
          </div>
        );
      }
    }
    

    Though, note that controlled inputs are generally recommended.

    0 讨论(0)
  • 2021-01-11 15:05

    As @Chris stated, you should create another component to optimize the rerendering to only the specified component.

    However, there are usecases where you need to update the parent component or dispatch an action with the value entered in your input to one of your reducers.

    For example I created a SearchInput component which updates itself for every character entered in the input but only call the onChange function only if there are 3 characters at least.

    Note: The clearTimeout is useful in order to call the onChange function only when the user has stopped typing for at least 200ms.

    import React from 'react';
    
    class SearchInput extends React.Component {
      constructor(props) {
        super(props);
        this.tabTimeoutId = [];
        this.state = {
          value: this.props.value,
        };
    
        this.onChangeSearch = this.onChangeSearch.bind(this);
      }
    
      componentWillUpdate() {
        // If the timoutId exists, it means a timeout is being launch
        if (this.tabTimeoutId.length > 1) {
          clearTimeout(this.tabTimeoutId[this.tabTimeoutId.length - 2]);
        }
      }
    
      onChangeSearch(event) {
        const { value } = event.target;
    
        this.setState({
          value,
        });
    
        const timeoutId = setTimeout(() => {
          value.length >= this.props.minSearchLength ? this.props.onChange(value) : this.props.resetSearch();
          this.tabTimeoutId = [];
        }, this.props.searchDelay);
    
        this.tabTimeoutId.push(timeoutId);
      }
    
      render() {
        const {
          onChange,
          minSearchLength,
          searchDelay,
          ...otherProps,
        } = this.props;
    
        return <input
          {...otherProps}
          value={this.state.value}
          onChange={event => this.onChangeSearch(event)}
        />
      }
    }
    
    SearchInput.propTypes = {
      minSearchLength: React.PropTypes.number,
      searchDelay: React.PropTypes.number,
    };
    SearchInput.defaultProps = {
      minSearchLength: 3,
      searchDelay: 200,
    };
    
    export default SearchInput;
    

    Hope it helps.

    0 讨论(0)
提交回复
热议问题