Get Started with Modern React: Step by Step
S02・V15: Lists and Keys (Part 2)
- We will show you how to extract a component with a key.
- We will demonstrate embedding “map()” within a JSX container.
- We will explain that keys must only be unique among their siblings.
Extracting Components with Keys
Keys only make sense in the context of the surrounding array.
Starting from the TodoList
example from the last video:
import React from "react";
import ReactDOM from "react-dom";
const todos = [
'Learn React',
'Wash dishes',
'Make bed',
];
const TodoList = props => {
const { todos } = props;
const listItems = todos.map((todo, index) => <li key={index}>{todo}</li>);
return <ul>{listItems}</ul>;
};
ReactDOM.render(<TodoList todos={todos} />, document.getElementById("root"));
We will extract a ListItem
component from the TodoList
component. We will destructure todo
from props
. And we will return the li
from the TodoList
component. Now we will add the ListItem
in its place.
import React from "react";
import ReactDOM from "react-dom";
const todos = [
'Learn React',
'Wash dishes',
'Make bed',
];
const ListItem = props => { const { todo } = props; return ( <li key={index}>{todo}</li> );};
const TodoList = props => {
const { todos } = props;
const listItems = todos.map((todo, index) => <ListItem todo={todo} />); return <ul>{listItems}</ul>;
};
ReactDOM.render(<TodoList todos={todos} />, document.getElementById("root"));
In our ListItem
component, index
is not defined. We may be tempted to use the todo
text as the key
instead.
const ListItem = props => {
const { todo } = props;
return (
<li key={todo}>{todo}</li> );
};
However, in Chrome’s Developer Console, we get a warning that each child in a list should have a unique “key” prop. Remember that keys only make sense in the context of the surrounding array.
We will remove the key
from the ListItem
component, since it is not in the context of the todos
array. Instead, we will add the key
within ListItem
element within the TodoList
component, which is in the context of the todos
array.
const ListItem = props => {
const { todo } = props;
return (
<li>{todo}</li> );
};
const TodoList = props => {
const { todos } = props;
const listItems = todos.map((todo, index) =>
<ListItem key={index} todo={todo} /> );
return <ul>{listItems}</ul>;
};
We can now see that the warning has disappeared. This is the correct way to specify the “key”. A good rule of thumb is that elements inside the map()
need keys.
Embedding map() in JSX
JSX allows embedding any expression in the curly braces of a JSX container, so we could inline the map()
result.
Sometimes this results in clearer code, but this style can also be abused.
Like in JavaScript, it is up to you to decide whether it is worth extracting a variable for readability.
Keep in mind that if the map()
body is too nested, it might be a good time to extract a component.
const ListItem = props => {
const { todo } = props;
return (
<li>{todo}</li>
);
};
const TodoList = props => {
const { todos } = props;
return (
<ul> {todos.map((todo, index) => <ListItem key={index} todo={todo} /> )} </ul> );
};
Unique among Siblings
Keys used within arrays should be unique among their siblings. However, they don’t need to be globally unique. We can use the same keys when we produce two different arrays.
We will render a Blog
element and pass in posts
as a prop.
import React from "react";
import ReactDOM from "react-dom";
ReactDOM.render(<Blog posts={posts} />, document.getElementById("root"));
Now, we will add some hard-coded posts
.
import React from "react";
import ReactDOM from "react-dom";
const posts = [ { id: 1, title: "Hello World", content: "Welcome to learning React!" }, { id: 2, title: "Installation", content: "Use yarn to install React." }];
ReactDOM.render(<Blog posts={posts} />, document.getElementById("root"));
Now, we will define the Blog
component. First, we will add a sidebar
. Inside sidebar
, we will map over each post
and display it in an unordered list. We will add the post.id
as the key
. Next, we will add a content
section, which will map over each post
, and display its title
and its content
. As we did in sidebar
, we will add the post.id
as the key
. We will return the sidebar
and the content
, separated by a hr
.
import React from "react";
import ReactDOM from "react-dom";
const 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: "Use yarn to install React." }
];
ReactDOM.render(<Blog posts={posts} />, document.getElementById("root"));
Note that we have used the same key in both the sidebar
and content
sections.
Keys serve as a hint to React, but they do not get passed to your components. That means that the key
prop cannot be destructured from props
in a component. If you need the value you passed as a key in your component as well, then you will need to explicitly pass it as a prop with a different name.
Summary
We showed you how to extract a component with a key. We demonstrated embedding map()
within a JSX container. And, we explained that keys must only be unique among their siblings.
Next Up…
In the next video, we will talk about using forms in React.