[React]: Handling Events
React
10/04/2019
Handling events in functional component (w/ hooks)
JSX
const Person = ({ name, age }) => { return <p>{`Name: ${name}`}</p>}
const App = () => { const [persons, setPersons] = React.useState([{ name: "A" }, { name: "B" }])
const changeNames = () => { setPersons([{ name: "C" }, { name: "D" }]) }
return ( <div> {persons.map(person => { return <Person name={person.name} age={person.age} /> })} <button onClick={changeNames}>Click</button> </div> )}
ReactDOM.render(<App />, document.getElementById("root"))
Use bind() when passing an argument
JSX
const Person = ({ name, age }) => { return <p>{`Name: ${name}`}</p>}
const App = () => { const [persons, setPersons] = React.useState([{ name: "A" }, { name: "B" }])
const changeNames = newName => { setPersons([{ name: newName }, { name: newName }]) }
return ( <div> {persons.map(person => { return <Person name={person.name} age={person.age} /> })} <button onClick={changeNames.bind(this, "Z")}>Click</button> </div> )}
ReactDOM.render(<App />, document.getElementById("root"))
Handling events in class component
App.js
JSX
const Person = ({ name }) => { return <p>{`Name: ${name}`}</p>}
class App extends React.Component { constructor(props) { super(props) this.state = { persons: [{ name: "A" }, { name: "B" }], } // bind(this) is necessary to make `this` work in the callback this.handleChangeNames = this.handleChangeNames.bind(this) }
handleChangeNames(e) { e.preventDefault() this.setState({ persons: [{ name: "C" }, { name: "D" }] }) }
render() { return ( <div> {this.state.persons.map(person => { return <Person name={person.name} age={person.age} /> })} <button onClick={this.handleChangeNames}>Click</button> </div> ) }}
ReactDOM.render(<App />, document.getElementById("root"))
e
is a synthetic event which is passed in as argument.e.preventDefault()
stops the default action of a selected element
Using arrow function(ES6) without bind()
App.js
JSX
const Person = ({ name }) => { return <p>{`Name: ${name}`}</p>}
class App extends React.Component { state = { persons: [{ name: "A" }, { name: "B" }], }
// Ensures `this` is bound within handleChangeNames handleChangeNames = e => { e.preventDefault() this.setState({ persons: [{ name: "C" }, { name: "D" }] }) }
render() { return ( <div> {this.state.persons.map(person => { return <Person name={person.name} age={person.age} /> })} <button onClick={this.handleChangeNames}>Click</button> </div> ) }}
ReactDOM.render(<App />, document.getElementById("root"))
Passing arguments
When passing arguments, you'd still have to bind the function. i.e.
JSX
const Person = ({ name }) => { return <p>{`Name: ${name}`}</p>}
class App extends React.Component { state = { persons: [{ name: "A" }, { name: "B" }], }
handleChangeNames = newName => { this.setState({ persons: [{ name: newName }, { name: "D" }] }) }
render() { return ( <div> {this.state.persons.map(person => { return <Person name={person.name} age={person.age} /> })} <button onClick={this.handleChangeNames.bind(this, "Z")}>Click</button> =================== OR =================== <button onClick={() => this.handleChangeNames("Z")}>Click</button> </div> ) }}
ReactDOM.render(<App />, document.getElementById("root"))
Arrow functions vs bind()
When passing arguments, below two lines are equivalent. arrow functions
and Function.prototype.bind
both will work; however, be aware that arrow function
callback gets created each time App.js
renders. This may result in inefficiency when callback is passed as prop to child components that can perform re-rendering. Thus, bind() is recommended over arrow functions.
JSX
<button onClick={this.handleChangeNames.bind(this, "Z")}>Click</button><button onClick={() => this.handleChangeNames.("Z")}>Click</button>