Debounce textarea input with react / shorten

I am trying to reverse a textarea value using react / redux and show the debuffed value in div#preview

, but after the first call to the function I get a synthetic event.

I have a reducer to handle the state of a textarea value that works as intended, but for simplicity, I wrote a local state in this snippet.

If there is a better way other than debounce

to avoid reacting to re-entry after each one keypress

, I'd love to find out. Thanks in advance.

class TextArea extends React.Component {
  constructor(props){
    super(props);
    this.state = {foo: ''}
  }
  
  handleInputChange = _.debounce((e) => {
    e.persist();
    let value = e.target.value;
    this.setState({foo: value});
  }, 300);

  render() {
    return (
      <div>
       <textarea onChange={(e)=>this.handleInputChange(e)} value={this.state.foo}></textarea>
       <p id="preview">{this.state.foo}</p>
      </div>
    );
  }
}


ReactDOM.render(
  <TextArea />,
  document.getElementById("react")
);
      

<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
      

Run codeHide result


+3


source to share


2 answers


You are getting this error because you are trying to execute an .persist()

event inside a timeout debounce

. When the timeout calls the callback, the synthetic event has already been fired. So you have to persist in the event outside of debounce.

However, your idea has another problem. Since the textbox is a controlled component, debouncing the updated value will cause the textbox to display (part of) the text only after using stopped input.

To prevent the control from having to update the state immediately and cancel the update for the view state (or dispatch of pruning actions).



For example:

class TextArea extends React.Component {
  constructor(props){
    super(props);
    this.state = { foo: '', controlled: '' }
  }
  
  updateFoo = _.debounce((value) => { // this can also dispatch a redux action
    this.setState({foo: value});
  }, 300);
  
  handleInputChange = (e) => {
    const value = e.target.value;
    
    this.setState({
      controlled: value
    });
    
    this.updateFoo(value);
  }

  render() {
    return (
      <div>
       <textarea onChange={ this.handleInputChange }
       value={this.state.controlled} />
       <p id="preview">{this.state.foo}</p>
      </div>
    );
  }
}


ReactDOM.render(
  <TextArea />,
  document.getElementById("react")
);
      

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="react"></div>
      

Run codeHide result


+1


source


Another answer has already touched on the problem of persisting the event. For the paragraph input aspect, you can read my blog post Practical Redux, Part 7: Handling Form Changes . In this article, I show a reusable component that can handle debouncing text input updates for the rest of the application, allowing them to re-render at once with the current value.



0


source







All Articles