Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ReactJS: Input fire onChange when user stopped typing (or pressed Enter key)
import React, { Component } from 'react';
import TextField from 'components/base/TextField';
const WAIT_INTERVAL = 1000;
const ENTER_KEY = 13;
export default class TextSearch extends Component {
constructor(props) {
super();
this.state = {
value: props.value
};
}
componentWillMount() {
this.timer = null;
}
handleChange(value) {
clearTimeout(this.timer);
this.setState({ value });
this.timer = setTimeout(::this.triggerChange, WAIT_INTERVAL);
}
handleKeyDown(e) {
if (e.keyCode === ENTER_KEY) {
::this.triggerChange();
}
}
triggerChange() {
const { value } = this.state;
this.props.onChange(value);
}
render() {
const { className } = this.props;
return (
<TextField
className={className}
placeholder={l('Search')}
value={this.state.value}
onChange={::this.handleChange}
onKeyDown={::this.handleKeyDown}
/>
);
}
}
@markkitz

This comment has been minimized.

Copy link

commented Jul 12, 2017

very useful. Thank you.

@danielezn

This comment has been minimized.

Copy link

commented Jul 27, 2017

👍

@erickakoyama

This comment has been minimized.

Copy link

commented Oct 13, 2017

👍

@bad6e

This comment has been minimized.

Copy link

commented Nov 7, 2017

Much thanks!

@clementtalleu

This comment has been minimized.

Copy link

commented Dec 23, 2017

muchas gracias <3

@barsbek

This comment has been minimized.

Copy link

commented Dec 25, 2017

Hi!

  1. Thanks for the gist!
  2. I have encountered double triggerChange method call, when i changed value and immediately pressed enter_key. So, i would suggest to add clearTimeout into handleKeyDown method.
handleKeyDown(e) {
    if (e.keyCode === ENTER_KEY) {
         clearTimeout(this.timer);
        ::this.triggerChange();
    }
}
@lisaljl

This comment has been minimized.

Copy link

commented Jan 17, 2018

Works well! thanks

@Shrikant9

This comment has been minimized.

Copy link

commented Jan 18, 2018

👍

@alexpacer

This comment has been minimized.

Copy link

commented Feb 8, 2018

This is exactly what I'm looking for! Much appreciated 👍

@juliofarah

This comment has been minimized.

Copy link

commented Feb 18, 2018

👍

@Alexgalinier

This comment has been minimized.

Copy link

commented Mar 9, 2018

That's really useful and exactly what i was looking for. Thanks !

@VincentNewkirk

This comment has been minimized.

Copy link

commented Mar 13, 2018

👍

@noushad-pp

This comment has been minimized.

Copy link

commented Mar 23, 2018

Sorry for the ignorance.
Can you please explain what :: before your function stands for?

@AOOlivares

This comment has been minimized.

Copy link

commented Mar 23, 2018

@noushad-pp
It's an ECMAScript function bind syntax as proposed here

@wootencl

This comment has been minimized.

Copy link

commented May 15, 2018

Minor note on using that :: bind syntax: Will take a slight performance hit as the function will need to be bound on every render. At least this is my understanding. To avoid this, binding should occur in the constructor.

@shenoyranjith

This comment has been minimized.

Copy link

commented Jul 3, 2018

Thanks! Really helpful!

@keshamtravels

This comment has been minimized.

Copy link

commented Aug 4, 2018

well done

@obbaeiei

This comment has been minimized.

Copy link

commented Aug 9, 2018

Thank you

But I have modified some code. It works with my project.

import React, { Component } from 'react'

const WAIT_INTERVAL = 1000
const ENTER_KEY = 13

class TextSearch extends Component {
  state = {
    value: ''
  }

  timer = null

  handleChange = e => {
    clearTimeout(this.timer)

    this.setState({ value: e.target.value })

    this.timer = setTimeout(this.triggerChange, WAIT_INTERVAL)
  }

  handleKeyDown = e => {
    if (e.keyCode === ENTER_KEY) {
      clearTimeout(this.timer)
      this.triggerChange()
    }
  }

  triggerChange = () => {
    const { value } = this.state

    this.props.onChange(value)
  }

  render() {
    const { ...rest } = this.props

    return (
      <input
        type={rest.type}
        className={rest.className}
        placeholder={rest.placeholder}
        value={this.state.value}
        onChange={this.handleChange}
        onKeyDown={this.handleKeyDown}
      />
    )
  }
}

export default TextSearch
@0t3dWCE

This comment has been minimized.

Copy link

commented Aug 15, 2018

👍

@0t3dWCE

This comment has been minimized.

Copy link

commented Aug 16, 2018

@obbaeiei, you should clear timeout inside handleKeyDown too. If your triggerChange will do fetch to backend (via action creator if u use redux), you will see two requests after Enter pressed.

@obbaeiei

This comment has been minimized.

Copy link

commented Aug 16, 2018

@0t3dWCE
I see. Thank you.

@prince1456

This comment has been minimized.

Copy link

commented Aug 22, 2018

Thank you its work fine for me too

@jose920405

This comment has been minimized.

Copy link

commented Dec 4, 2018

Any way to do this without this.setState({ value });?

Because in reality a change is made in the local state immediately and then a props is dispatched to the parent component.

@ashishcodes4

This comment has been minimized.

Copy link

commented Jan 29, 2019

couldn't thank you enough for this, however I was wondering if there is any better way of doing the same.

@ashishcodes4

This comment has been minimized.

Copy link

commented Jan 29, 2019

Thank you

But I have modified some code. It works with my project.

import React, { Component } from 'react'

const WAIT_INTERVAL = 1000
const ENTER_KEY = 13

class TextSearch extends Component {
  state = {
    value: ''
  }

  timer = null

  handleChange = e => {
    clearTimeout(this.timer)

    this.setState({ value: e.target.value })

    this.timer = setTimeout(this.triggerChange, WAIT_INTERVAL)
  }

  handleKeyDown = e => {
    if (e.keyCode === ENTER_KEY) {
      clearTimeout(this.timer)
      this.triggerChange()
    }
  }

  triggerChange = () => {
    const { value } = this.state

    this.props.onChange(value)
  }

  render() {
    const { ...rest } = this.props

    return (
      <input
        type={rest.type}
        className={rest.className}
        placeholder={rest.placeholder}
        value={this.state.value}
        onChange={this.handleChange}
        onKeyDown={this.handleKeyDown}
      />
    )
  }
}

export default TextSearch

Hey, can you explain what is type= rest.type attribute in input element.

@ashishcodes4

This comment has been minimized.

Copy link

commented Jan 29, 2019

Thank you
But I have modified some code. It works with my project.

import React, { Component } from 'react'

const WAIT_INTERVAL = 1000
const ENTER_KEY = 13

class TextSearch extends Component {
  state = {
    value: ''
  }

  timer = null

  handleChange = e => {
    clearTimeout(this.timer)

    this.setState({ value: e.target.value })

    this.timer = setTimeout(this.triggerChange, WAIT_INTERVAL)
  }

  handleKeyDown = e => {
    if (e.keyCode === ENTER_KEY) {
      clearTimeout(this.timer)
      this.triggerChange()
    }
  }

  triggerChange = () => {
    const { value } = this.state

    this.props.onChange(value)
  }

  render() {
    const { ...rest } = this.props

    return (
      <input
        type={rest.type}
        className={rest.className}
        placeholder={rest.placeholder}
        value={this.state.value}
        onChange={this.handleChange}
        onKeyDown={this.handleKeyDown}
      />
    )
  }
}

export default TextSearch

Hey, can you explain what is type= rest.type attribute in input element.

Never mind, got it, its the rest/spread thing you are using to pass the props passed to the component.
Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.