Rendering Dynamic Data with Components
Course: React JS & Tailwind CSS - Full Course
Introduction
In real-world apps, you rarely know ahead of time exactly how many items you’ll need to render. Whether it’s tasks in a todo app, products in a store, or posts in a blog, your data usually comes from a database or an API.
That means hardcoding each component with individual props quickly becomes unmanageable. Instead, React allows us to take an array of objects and dynamically render components for each item. This keeps your code clean, organized, and ready to handle any amount of data.
In this section, we’ll explore how to take a list of data and turn it into reusable components using .map()
. By the end, you’ll understand the pattern that’s used in almost every React app and get a hands-on challenge to practice it with a TaskItem
component for your task tracker app.
Mapping Data into Components
In the previous lesson, we created a reusable UserCard
component but we were still manually passing information into those cards.
This works fine for a few users, but it’s not scalable. What if you have 100 users coming from a database? You wouldn’t want to manually write a <UserCard>
for each one.
Instead, you can store your data in an array of objects (like a database) and use .map()
to render your components dynamically (this is where knowing JavaScript fundamentals comes in handy):
function App() {
const users = [
{ id: 1, name: "Alice Johnson", email: "alice@example.com", phone: "123-456-7890" },
{ id: 2, name: "Bob Smith", email: "bob@example.com", phone: "987-654-3210" },
];
return (
<div>
{users.map(user => (
<UserCard
name={user.name}
email={user.email}
phone={user.phone}
/>
))}
</div>
);
}
As you can see, we use .map()
to loop over the array and each UserCard
gets its data from the object.
However, if you hit save you might see an error like this in your console: Warning: Each child in a list should have a unique "key" prop.
Although your component may still render this could lead to some unexpected behavior.
Why Keys are Necessary
When we render a list of components using .map()
, React needs a way to identify each component uniquely. This is important for performance and correctness. If a component is added, removed, or changed, React uses these keys to decide which components to update in the DOM.
To address this, we'll need to include a key
prop. It is important to note, keys need to be unique among siblings and stable (does not change).
The fix is quite simple, we just need to provide a unique "key" for each component. Most databases will have a unique identifier for their objects, and we can assign it to the key like so:
{users.map((user) => (
<UserCard
key={user.id}
name={user.name}
email={user.email}
phone={user.phone}
/>
))}
Challenge
Now it’s your turn!
Your task:
- Create a new component called
TaskItem
in its own file. - The component should accept a task object as a prop and render:
- The task text
- A Mark Complete button
- An Edit button
- A Delete button
- In
App.jsx
, create an array of task objects and map over it to render aTaskItem
for each task. - Don’t forget the
key
prop for eachTaskItem
.
Note: You don’t need to add functionality to the buttons yet. This challenge is just about building reusable components and rendering them from data.
Try to write this yourself before looking at the solution!
Solution
First create the an array of task objects in your App.jsx
:
const tasks = [
{ id: 1, text: "Buy groceries" },
{ id: 2, text: "Walk the dog" },
{ id: 3, text: "Finish React course" },
]
Then create a new component called TaskItem.jsx
in the components folder:
function TaskItem({ task }) {
return (
<div key={task.id}>
<p>{task.text}</p>
<button>Mark Complete<button/>
<button>Edit</button>
<button>Delete</button>
</div>
)
}
export default TaskItem
After that, import your TaskItem component and map each task into TaskItem:
{tasks.map((task) => (
<TaskItem key={task.id} task={task} />
))}