[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>

WRITTEN BY

Keeping a record