Week 4 - React Fundamentals

Why React?

Setting up a React project with Vite

Components

JSX

Props

Rendering lists

Conditional rendering

The mental model: how React renders (2)

Practice

Assignment

Front end Track

Rendering Lists

Most real apps render lists of things — products, users, messages, notifications. In React, you render lists by transforming an array of data into an array of JSX elements using .map().

This is the single most-used pattern in all of React.

https://www.youtube.com/watch?v=fkl1Kn_QWCI

The Pattern

const fruits = ['apple', 'banana', 'cherry'];

return (
  <ul>
    {fruits.map((fruit) => (
      <li key={fruit}>{fruit}</li>
    ))}
  </ul>
);

Three things to notice:

  1. The whole .map() call is wrapped in {} — a JavaScript expression inside JSX
  2. .map() returns an array, and React renders an array of JSX elements in order
  3. Each element has a key prop — this is required, and React will warn you if it's missing

Why Keys Matter

React uses key to track which items are which across re-renders. When your list changes — items added, removed, or reordered — React uses keys to figure out the minimal set of DOM updates needed. Without keys, React has to re-render the entire list every time anything changes.

// ✅ Good — stable unique ID from your data
{users.map((user) => (
  <UserCard key={user.id} {...user} />
))}

// ⚠️ Only acceptable when the list never changes order or length
{users.map((user, index) => (
  <UserCard key={index} {...user} />
))}

// ❌ New key on every render — React re-mounts the component each time
{users.map((user) => (
  <UserCard key={Math.random()} {...user} />
))}

Key rules:

The key goes on the outermost element returned from the .map() callback — in the examples above, that's <UserCard>, not something inside it.

<aside> ⚠️

Warning

Warning: Each child in a list should have a unique "key" prop.

You'll see this in the console when you forget a key. Find the .map() that's missing it and add key={item.id} (or whatever uniquely identifies that item) to the element you return.

</aside>

Filtering and Sorting

.map() is plain JavaScript, so you can chain .filter(), .sort(), and any other array method before it:

const onlineUsers = users
  .filter((user) => user.isOnline)
  .sort((a, b) => a.name.localeCompare(b.name));

return (
  <ul>
    {onlineUsers.map((user) => (
      <li key={user.id}>{user.name}</li>
    ))}
  </ul>
);

Do the filtering and sorting before the return, assign the result to a variable, then map over that. Keeps your JSX readable.

<aside> ⌨️

Hands On

Given this array:

const cities = [
  { id: 1, name: 'Amsterdam', population: 921000 },
  { id: 2, name: 'Rotterdam', population: 651000 },
  { id: 3, name: 'Utrecht', population: 361000 },
  { id: 4, name: 'Den Haag', population: 548000 },
];

Render a list of city names sorted alphabetically. Then add a second list showing only cities with a population above 600,000. Make sure both lists have proper keys.

</aside>

Always Handle the Empty State

When the array is empty, your .map() returns nothing and the screen shows a blank space. That's confusing for users. Always handle it:

return (
  <div>
    {users.length === 0 ? (
      <p>No users yet.</p>
    ) : (
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    )}
  </div>
);

<aside> 💡

Info

For longer lists, you might also want to handle a loading state (data is being fetched) and an error state (the fetch failed). We'll get to that when we cover data fetching in week 10. The pattern is the same — just more conditions to check before you render the list.

</aside>

A Complete Example

interface BookProps {
  title: string;
  author: string;
  year: number;
}

function Book({ title, author, year }: BookProps) {
  return (
    <li>
      <strong>{title}</strong> — {author} ({year})
    </li>
  );
}

function BookList() {
  const books = [
    { id: 1, title: 'Sapiens', author: 'Yuval Noah Harari', year: 2011 },
    { id: 2, title: 'Clean Code', author: 'Robert C. Martin', year: 2008 },
    { id: 3, title: 'The Pragmatic Programmer', author: 'Hunt & Thomas', year: 1999 },
  ];

  return (
    <section>
      <h2>My bookshelf ({books.length} books)</h2>
      {books.length === 0 ? (
        <p>No books yet.</p>
      ) : (
        <ul>
          {books.map((book) => (
            <Book key={book.id} {...book} />
          ))}
        </ul>
      )}
    </section>
  );
}

BookList owns the data. Book receives it as props and renders it. The key sits on <Book> — the outermost element in the .map() callback. This is the pattern you'll use throughout the course.

<aside> ⌨️

Hands On

Build a ProductCard component with props title, price, description, and available (boolean). Then build a Shop component that maps over an array of at least four product objects and renders a ProductCard for each. Add an empty state message for when the array is empty.

Stretch: filter the list to only show available products. You'll need to hardcode a filtered array for now — next week you'll learn to do this dynamically with state.

</aside>

<aside> 🎉

Celebration

Lists, components, and props working together is the core loop of building UIs in React. You now have all three. Everything from here builds on this foundation.

</aside>

Additional Resources

Videos

Reading

Interactive


The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

CC BY-NC-SA 4.0 Icons

Built with ❤️ by the HackYourFuture community · Thank you, contributors

Found a mistake or have a suggestion? Let us know in the feedback form.