Very few real interfaces show just one thing. Feeds, product grids, todo lists, tables — almost everything is a list of similar items rendered from an array of data. React does not have a special "list" syntax; it just leans on plain JavaScript array methods, mainly map().

Rendering an array with map()

const fruits = ["Apple", "Banana", "Cherry"];

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

map() transforms each array item into a piece of JSX, and the curly braces drop that whole array of elements straight into the markup. React handles arrays of elements just fine inside JSX.

Why the key prop matters

Notice the key={fruit} attribute. React uses keys to figure out which items changed, were added, or were removed between renders, instead of re-rendering the entire list from scratch every time. Skip it and React will still render the list, but it will warn you in the console, and worse, list items can end up mismatched with the wrong data after an update — a classic bug that is confusing to track down later. A stable, unique id from your data is always a better key than the array index.

const todos = [
  { id: 1, text: "Learn React" },
  { id: 2, text: "Build a project" },
];

todos.map((todo) => <li key={todo.id}>{todo.text}</li>);

Handling events

React event handlers look a lot like plain HTML onclick attributes, but camelCased and pointing at an actual function reference, not a string:

function SearchBox() {
  function handleChange(event) {
    console.log("Typed:", event.target.value);
  }
  return <input onChange={handleChange} placeholder="Search..." />;
}

React wraps the browser's native event in its own SyntheticEvent object so handlers behave consistently across browsers, but day to day it behaves just like the DOM event you already know — event.target.value for an input's current text, event.preventDefault() to stop a form from submitting the old-fashioned way, and so on.

Combining both: a filterable list

function FilterableList() {
  const [query, setQuery] = useState("");
  const items = ["React", "Docker", "Java", "Spring Boot"];
  const filtered = items.filter((item) =>
    item.toLowerCase().includes(query.toLowerCase())
  );

  return (
    <div>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      <ul>
        {filtered.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

That one small component already combines state, an event handler and a rendered list — which is, honestly, most of what a huge share of real React screens are doing under the hood. Next up: useEffect, for the things that need to happen outside of rendering, like fetching data from a real API.