question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Debounce onChange events

See original GitHub issue

Currently, for each keystroke in an input, a distinct action is dispatched. This results in a rather large action log that I’d like to avoid. Is there a way to effectively debounce the props.input.onChange function? I’ve tried the following without success:

const DebouncedInput1 = props =>
  <input
    {...props.input}
    onChange={debounce(props.input.onChange, 200)}/>

// -> debounced function is re-created on each render


class DebouncedInput2 extends Component {
  constructor(props) {
    super(props)
    this.debounced = debounce(props.input.onChange, 200)
  }

  render() {
    return (
      <input
        {...this.props.input}
        onChange={this.debounced}/>
   )
 }
}

// -> react warns about reused synthetic events (and using `event.persist()` has no effect)

Thanks in advance for your feedback.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:10
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

15reactions
stefkcommented, Sep 25, 2016

@smirea, thanks a lot for your detailed explanation. I didn’t manage to have the validation working correctly using only defaultValue (I’m still to new to this, I may have done a mistake somewhere) but your answer put me on the good track. Here’s what I ended up with:

class DebouncedInput extends Component {
  constructor(props) {
    super(props)
    this.state = {value: props.input.value}
    this.lastPropValue = props.input.value

    this.debouncedOnChange = debounce(event => {
      props.input.onChange(event.target.value)
    }, 200);

    this.handleChange = event => {
      event.persist()
      this.setState({value: event.target.value})
      this.debouncedOnChange(event)
    }
  }

  getValue() {
    const value = this.props.input.value !== this.lastPropValue ?
      this.props.input.value :
      this.state.value

    this.lastPropValue = this.props.input.value

    return value
  }

  render() {
    return (
        <input
          type="text"
          value={this.getValue()}
          onChange={this.handleChange}/>
    )
  }
}

It’s a controlled component which manages the input value using both state and props. It might look cumbersome at first but it’s apparently what’s required to correctly handle:

  • debounced changes
  • validation
  • time-travelling
5reactions
smireacommented, Sep 24, 2016

when you do <Field name='foo' component={DebouncedInput1} /> the input object you pass along contains a value prop that is passed directly from your redux state. That makes your input a controlled component which basically means its value only gets updated as a result of a state change, ergo you need to dispatch an action on every key press so the state gets update. Therefore debouncing doesn’t work

If you want to avoid triggering an action on every key (due to performance or smaller action log), you have to make it an uncontrolled field by not passing the onChange and the value props. This will update your input only on blur:

const renderTextInput = ({input: {value, onChange, ...input}}) =>
    <input type='text' {...input} defaultValue={value} /> {/** use defaultValue instead **/}

<Field name='foo' component={renderTextInput} />

This has a few effects since the state will now be updated on blur:

  • errors will show up / be cleared on blur
  • your input will not react to state changes, aka you lose the ability to update the value via the reducer unless you unmount the field
Read more comments on GitHub >

github_iconTop Results From Across the Web

Debouncing events with React - Medium
The above code passes a debounced function as the event callback to the onChange event. The _.debounce function ensures that the actual onChange...
Read more >
How to Correctly Debounce and Throttle Callbacks in React
Fortunately, debouncing and throttling techniques can help you control the invocation of the event handlers. In this post, you'll learn how ...
Read more >
javascript - Debounce onChange - Stack Overflow
You are creating a debounced instance on every event call. Try creating one instance of debounced function and use it in your handler....
Read more >
javaScript - debounce onchange input event - CodePen
Onchange Event used on user input fields. Only works on <input>, <select>, and <textarea>. Demo: Type into the inputs or click the button....
Read more >
Implement Debouncing in React in 3 Different Ways
Debouncing is used for optimizing the performance of a web app. ... debouncing by implementing it on an input box with an onChange...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found