EduFlow
React Fundamentals
0%

Section 2 · Components & Props

Thinking in Components

16 min3 min readChoose wisely

Lesson at a glance

Turn a screen mockup into a component tree, build a static version first, and identify the minimal state the Watchlist needs before writing any interactive code.

  1. 1Draw boxes, name them
  2. 2When to split, and when not to
  3. 3Build the static version first
  4. 4Find the minimal state
  5. 5Where the data lives

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

Here’s the Watchlist you’re building, described as a designer would hand it over: a header with the title and “3 to watch”; a form with a title input and an Add button; a row of filter buttons (All, To watch, Watched); and a list of movies, each with its title, year and a checkbox to mark it watched. When the list is empty, a friendly message replaces it.

Before you write a line of code, decide what the components are. It’s the most important design step in a React app, and it’s done with a pen.

Draw boxes, name them

Take the mockup and draw a box around every piece that does one job. Then name each box as a noun, the way you’d name a function.

App is the root. Its children are Header, AddMovieForm, FilterBar and MovieList. Header contains WatchCount. MovieList contains several MovieItem components, or EmptyState when there are no movies. App Header AddMovieForm FilterBar MovieList WatchCount MovieItem ×n EmptyState
The Watchlist as a component tree

Nested boxes become a tree. App owns the whole screen. MovieList renders either many MovieItems or one EmptyState. This tree is the plan for the rest of the course; you’ll build each box as a component.

When to split, and when not to

Split a piece into its own component when at least one of these is true:

  • It repeats. MovieItem appears once per movie. Writing it once is the point.
  • It has its own job. AddMovieForm handles typing and submitting. Nothing else needs to know how.
  • The parent is getting hard to read. If you scroll to understand a component, extract a named piece.

Don’t split just because you can. A component that only wraps one <span> adds a file, an import and a name to remember, and gives nothing back. Experienced teams often keep a component at 100 lines rather than splitting it into five 20-line ones that are only used together. Start a little bigger and extract when one of the three reasons appears.

Build the static version first

With the tree drawn, build it with hard-coded data and no interactivity. Pass data down from the top so the shape is right from the start:

src/App.jsx
const MOVIES = [
  { id: 1, title: 'Arrival', year: 2016, watched: true },
  { id: 2, title: 'Past Lives', year: 2023, watched: false },
  { id: 3, title: 'Paddington 2', year: 2017, watched: false },
];

export default function App() {
  return (
    <main>
      <Header movies={MOVIES} />
      <AddMovieForm />
      <FilterBar />
      <MovieList movies={MOVIES} />
    </main>
  );
}
// …Header, AddMovieForm, FilterBar and MovieList defined below

Building the static version is mostly typing, and it gets the structure and markup right while nothing moves. Adding interactivity is mostly thinking. Doing both at once is how components end up tangled.

Find the minimal state

Next, list every piece of data in the app and ask three questions about each. Does it stay the same over time? Is it passed in from a parent? Can you calculate it from other data? If the answer to any of them is yes, it isn’t state.

For the Watchlist:

Data State? Why
The list of movies Yes Changes when you add, remove or mark one
The current filter Yes Changes when you click a filter button
Text typed in the form Yes Changes as you type
Number left to watch No Calculated from the movies
Movies currently visible No Calculated from movies + filter

Three pieces of state, two derived values. Keeping state minimal is the single habit that prevents the most bugs in React apps. Every extra piece of state is a second copy of the truth that can disagree with the first.

Where the data lives

The movies are needed by Header (for the count) and MovieList (to show them). The rule: data lives in the closest common parent of every component that needs it, which here is App. It flows down as props. When a child needs to change it, the parent passes down a function to call. You’ll do exactly that in Section 3.

Next, you’ll learn props properly: how to pass data into components, set defaults and keep components reusable.

Key takeaways

  • Draw boxes around the mockup and name each box; nested boxes become a component tree.
  • Split a component when a piece is reused, has its own job, or makes the parent hard to read, not by default.
  • Build a static version from hard-coded data first, then add interactivity.
  • Keep the minimal state; anything you can calculate from other data, such as a count or a filtered list, is derived, not state.

Further reading

Check your understanding

4 questions

Question 1 of 4

The Watchlist needs to show how many movies are unwatched. Where should that number come from?

Question 2 of 4

A teammate splits the movie card into MovieTitle, MovieYear, MovieTitleWrapper and MovieYearText, each wrapping one tag. What’s the best review comment?

Question 3 of 4

In the Watchlist tree, App contains Header, AddMovieForm, FilterBar and MovieList, and MovieList contains many MovieItems. Which components need the movies array?

Question 4 of 4

Why build a static version of the Watchlist with hard-coded data before adding state?

Practice

Choose wisely

Find the minimal state

The Watchlist gets two new features. Each movie can now have a star rating from 1 to 5 that you set by clicking stars, and a dropdown lets you sort the list by title or by year. The header also shows the average rating of the movies you’ve watched.

Which of these should be stored in state? Pick every one that is truly state; leave out anything that’s derived.

Find the minimal state