React element event handling is very similar to that of DOM elements, but there is a slight difference in syntax.
React events are named using camelCase, rather than all lowercase.
When using JSX syntax, you need to pass a function as the event handler, rather than a string.
1. Event Handling#
1. Event Binding#
React element event handling is similar to that of DOM elements, but there are some syntactical differences, for example:
Traditional HTML: Wrapped in double quotes, must be followed by parameters.
<button onclick="myfun()">Click</button>
React: Wrapped in curly braces, not followed by parameters.
<button onclick={myfun}>Click</button>
A complete event function code is as follows:
class Demo extends React.Component {
render() {
// Event function
function myfun() {
alert('hello, world')
}
return (
// Bind event
<button onClick={this.myfun}>
Activate Lasers
</button>
)
}
}
ReactDOM.render(
<Demo />,
document.getElementById('root')
)
If the method does not have
()
, you need to bindthis
to that method.
2. Preventing Default Behavior#
Another difference in React is that you cannot prevent default behavior by returning false; React provides a property — preventDefault
, which can be used to prevent script execution.
Let's look at the comparison between traditional HTML and React.
<a href="#" onclick="alert('Should it pop up?');return false">
Click me
</a>
Simply writing false can prevent script execution.
React prevents script execution through the preventDefault property:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
2. Conditional Rendering#
In React, you can create different components to encapsulate various behaviors you need, and then, based on the different states of the application, you can render only the content corresponding to the current state.
Conditional rendering in React is similar to that in JavaScript, using the if
operator to represent the current state of the element, and then letting React update the UI based on them.
Using if..else Statements for Conditional Rendering#
First, let's write an example of conditional rendering, defining two components, and then judging the truthiness of the variable isLoggedIn
in the Greeting
component to let the browser render either the UserGreeting
or GuestGreeting
component.
// App.js
import React, { Component } from 'react'
export default class App extends Component {
render() {
function UserGreeting(props) {
return <h3>Welcome back!</h3>;
}
function GuestGreeting(props) {
return <h3>Please sign up.</h3>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
return (
<div>
<Greeting isLoggedIn={false} />
</div>
)
}
}
Finally, the variable isLoggedIn
is defined as false
, so the browser renders GuestGreeting
.
How to Prevent Conditional Rendering?#
In some cases, we may want to hide a component even if it has already been rendered by other components. We can return null
from the render
method to prevent the component from rendering.
In the following example, <WarningBanner />
will conditionally render based on the value of warn
in the props. If the value of warn
is false
, then the component will not render:
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true};
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
3. Rendering Lists#
First, let's look at a piece of code where we use the map()
function to double each item in the array, resulting in a new array doubled
which we print out.
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
// [2,4,6,8,10]
In React, the process of converting an array into a list of elements is similar.
First, we traverse the numbers
array using the map()
method, turning each element in the array into an <li>
tag, and finally assigning the resulting array to listItems
.
Then we return {listItem}
.
// Map.js
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
After running, the browser displays an unordered list of 1-5.
1. Separating Components#
The above is a basic example of list rendering, but the data is hardcoded. Next, we will refactor the array into a component, so that we can easily call it when rendering the array later.
// Map.js
export default class Map extends Component {
render() {
// Separate the NumberList component as the component for transforming the array
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
// Pass in the required data
const numbers = [1, 2, 3, 4, 5, 6, 7];
return (
<div>
<NumberList numbers={numbers} />
</div>
)
}
}
2. Key#
After running the code, the page displays normally, but the console reports an error: Each child in a list should have a unique "key" prop.
, which means that when you create an element, you must include a special key
property.
Now assign a key to each list element:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
3. Using ID as Key#
The key
helps React identify which elements have changed, such as being deleted or added, so each element should have a unique identifier, which is the key
.
The key
of an element is best as a unique string that the element has in the list. Typically, we use the id
from the data as the element's key
:
// Map.js
export default class Map extends Component {
render() {
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.id}> // Assign key
{number.text}
</li>
);
return (
<ul>{listItems}</ul>
);
}
// Pass in data
const numbers = [
{id: 1,text: 1},
{id: 2,text: 2},
{id: 3,text: 3},
{id: 4,text: 4},
{id: 5,text: 5}
];
return (
<Fragment>
<NumberList numbers={numbers} />
</Fragment>
)
}
}
4. Can Index Be Used as Key?#
When elements do not have a defined id, you can reluctantly use the element index index
as the key
:
const todoItems = todos.map((todo, index) =>
// Only use index as key when there is no defined id
<li key={index}>
{todo.text}
</li>
);
If the order of list items may change, we do not recommend using the index as the key
value, as this can lead to performance degradation and may cause issues with component state.
5. Extracting Components with Key#
For example, if you extract a ListItem
component, you should keep the key
on the <ListItem />
element in the array, rather than placing it on the <li>
element inside the ListItem
component.
Incorrect Usage:
function ListItem(props) {
const value = props.value;
return (
// Incorrect! You do not need to specify key here:
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Incorrect! The key of the element should be specified here:
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
Correct Usage:
function ListItem(props) {
// Correct! No need to specify key here:
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Correct! Key should be specified in the context of the array
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
React: A good rule of thumb is that elements in the map() method need to set the key property.
6. Key Must Be Unique Only Among Sibling Nodes#
The key
used in array elements should be unique among its sibling nodes. However, they do not need to be globally unique. When we generate two different arrays, we can use the same key
values:
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{content}
</div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
7. Rendering Lists in Vue#
In Vue, rendering lists uses the special directive v-for
, which also has related usage of key
.
In React, we use the map()
method to traverse the array and then render the list.