It is fair to say at least 1/3 of all reactjs questions posted on StackOverflow can be solved by understanding simple DOM event handler binding.
Typically, they look like this:
class EmailSignup extends React.Component {
state = {
email: ''
}
handleChange({target}) {
this.setState({email: target.value})
}
render(){
return <input onChange={this.handleChange} value={this.state.email} />
}
}
And then comes the dreaded error and a new forum post:
TypeError: Cannot read property ‘setState’ of undefined on line 8.
This is an event handler, contextually this
will be the event.target
by default. Patterns to solve it are so many…
1. Preferred way is to bind the method to your instance in your constructor.
constructor(props){ super(props) this.state = { email: props.email } this.handleChange = this.handleChange.bind(this) }
It is preferred as it happens once only at instantiation of the component, so it’s cheap.
2. Use an arrow function to keep contextual this
. This works but makes a new function on every render of your component (tree)
render(){ return <input onChange={event => this.handleChange(event)} value={this.state.email} /> }
3. Use local binding. It works but also makes a new function on every render of your component (tree)
render(){ return <input onChange={this.handleChange.bind(this)} value={this.state.email} /> }
4. Use the new experimental (not in ECMAScript yet[tm]) bind syntax ::
. Essentially, sugar for #3
render(){ return <input onChange={::this.handleChange} value={this.state.email} /> }
5. Use the new Class property transforms
// just inside your class definition - just like the state = handleChange = ({target}) => { this.setState({email: target.value}) }