Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 72

Building a Reusable Product Card Component

Recommended resources

Hello! Welcome to the next step in building our e-commerce application.

In the last lesson, we successfully fetched a list of products from an API and displayed them on our ProductsPage. However, you might have noticed that the code for rendering each product was written directly inside the .map() loop. While functional, this approach isn't ideal for larger applications as it mixes data-handling logic with presentation and isn't reusable.

Today, we will address this by applying a core principle of React: componentization. Your goal for this lesson is to create a reusable ProductCard component to display individual product information. This will make our code cleaner, more modular, and easier to maintain—a crucial skill for any React developer.

Understanding Props: How Components Receive Data

Before we build our component, we need to understand how we'll pass the product data (like its title, price, and image) into it. In React, this is done using props (short for properties).

Props allow you to pass data from a parent component down to a child component. This data flow is unidirectional, meaning it only goes one way: from parent to child. This design choice helps make your application's data flow predictable and easier to debug.

To get a solid grasp of this concept, let's start with a short reading.

React - Passing Data Between Components

This article from The Odin Project provides a clear and concise introduction to props. It explains the concept and syntax you'll be using in just a moment.

Please read the sections titled 'Introduction', 'Data transfer in React', 'Using props in React', and 'Prop destructuring'. Pay close attention to how data flows one-way and how destructuring makes your component code cleaner.


Building the ProductCard Component

Now that you understand props, let's create our ProductCard. It's a common convention in React projects to create a src/components directory to store reusable components like this.

  1. Create a new folder named components inside your src directory.
  2. Inside src/components, create a new file named ProductCard.jsx.

This component's job will be to receive product details via props and render them in a consistent layout. The following video demonstrates this exact process.

Shopping Cart In React Js For Newbies

This video shows the creation of a mock product list and then a ProductCard component to display each item. We'll focus on the part where the component itself is created and set up to receive data via props.

Watch from 07:43 to 10:18. The first part (until 09:13) shows a mock data structure, which is very similar to the data we are getting from our API. The second part (from 09:34) demonstrates creating the ProductCard component and defining how it receives data. This is exactly what we are about to do.


Your Turn: Code the ProductCard

Let's write the code for our new component. Open src/components/ProductCard.jsx and add the following:

// src/components/ProductCard.jsx

// We accept an object of props as an argument.
// Using ES6 destructuring, we can pull out the specific properties we need: image, title, and price.
export default function ProductCard({ image, title, price }) {
  return (
    <div style={{ border: '1px solid #ccc', padding: '1rem', textAlign: 'center' }}>
      <img
        src={image}
        alt={title}
        style={{ width: '100%', height: '150px', objectFit: 'contain' }}
      />
      <h3 style={{ fontSize: '1rem', height: '4rem', overflow: 'hidden' }}>
        {title}
      </h3>
      <p style={{ fontWeight: 'bold' }}>
        ${price}
      </p>
    </div>
  );
}

Let's break this down:

  • export default function ProductCard({ image, title, price }): We define a standard functional component. By destructuring the props object directly in the function's parameters, we get direct access to image, title, and price as variables. This is the clean pattern you read about.
  • JSX Structure: The JSX is nearly identical to the div we had inside the .map() loop in the previous lesson. The key difference is that it's now a self-contained, reusable unit.
  • Using Props: The destructured props (image, title, price) are used to populate the src attribute of the image, the text content of the heading, and the price paragraph.

Testing the Component

How can we be sure our component works before integrating it into the ProductsPage? We can temporarily render it with some "mock" (hardcoded) data.

Open your src/App.jsx file and add an import for the new component. Then, render it inside your Layout with some sample props.

// src/App.jsx
import Layout from './components/Layout';
import ProductsPage from './pages/ProductsPage';
import ProductCard from './components/ProductCard'; // 1. Import the new component
import { Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        {/* You can add other routes here later */}
        <Route path="products" element={<ProductsPage />} />
        
        {/* 2. Add the test component here */}
        <Route index element={
          <div style={{padding: '2rem'}}>
            <h2>My Test Card</h2>
            <ProductCard 
              title="A Test Product - Very Long Title to See How It Wraps or Overflows"
              price={99.99}
              image="https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg"
            />
          </div>
        } />
      </Route>
    </Routes>
  );
}

export default App;

Now, when you run your app and navigate to the home page (/), you should see your ProductCard rendered with the test data. This confirms it's working as expected. Once you've verified it, you can remove the test code and import from App.jsx.


Conclusion

Excellent work! You've successfully created your first reusable React component from scratch. This is a fundamental building block for creating scalable and maintainable applications.

Key Takeaways:

  • Componentization: Breaking down your UI into small, reusable components (like ProductCard) is a core principle of React development.
  • Props: Components receive data from their parents via a props object.
  • Unidirectional Data Flow: Data in React flows in one direction, from parent to child, which makes apps more predictable.
  • Prop Destructuring: Using destructuring in a component's function signature is a common and clean way to access the props you need.

Preview of the Next Lesson:

Our ProductCard component is ready and waiting. In the next lesson, we will go back to our ProductsPage.jsx file and replace the hardcoded display logic in our .map() function. We'll learn how to render a grid of these new, reusable cards using the live data from our API, completing the refactor of our product list.