Chapter 30 — React Components, Props and State
Section 1 — What a component is
A React component is a reusable piece of user interface, written as a function that returns what should appear on screen. That definition is worth unpacking slowly, because a React component shows up in almost every React screen you will build. When you can say in plain words what a React component does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Components let you break a large screen into small, named parts that you can understand, test, and reuse.
Working with a React component usually follows a small, repeatable pattern. First, name one job for the component. Next, write a function that returns its markup. Finally, use that component wherever that job is needed. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Greeting() {
return <h1>Hello, welcome back.</h1>;
}
Read the example from the top down. Greeting does one job only: it shows a welcome heading, and it needs no outside data to do that job well. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with a React component is making one component do five unrelated jobs, which makes it hard to read and harder to reuse. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: In plain words, what is a React component?
Section 2 — Function components
A function component is an ordinary JavaScript function whose name starts with a capital letter and which returns markup describing the interface. That definition is worth unpacking slowly, because function components shows up in almost every React screen you will build. When you can say in plain words what function components does, you can decide where it belongs, what data it needs, and what should happen when that data changes. They are the standard way to write components in modern React, because they are simple to read and easy to combine with hooks.
Working with function components usually follows a small, repeatable pattern. First, write a function with a capitalised name. Next, return JSX that describes the output. Finally, call the component from another component like a tag. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Welcome() {
return <p>Welcome to the course.</p>;
}
Read the example from the top down. Welcome is a plain function, so you can trace it like any other function: it runs, it returns markup, and React displays that markup. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with function components is starting a component name with a lowercase letter, which makes React treat it as an ordinary HTML element instead. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why must a component name start with a capital letter?
Section 3 — JSX in components
JSX is a syntax extension that lets you write markup that looks like HTML inside JavaScript, and React turns it into the elements shown on screen. That definition is worth unpacking slowly, because JSX in components shows up in almost every React screen you will build. When you can say in plain words what JSX in components does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It keeps structure close to the logic that decides it, so a component reads as one coherent description of a piece of interface.
Working with JSX in components usually follows a small, repeatable pattern. First, write markup inside the return statement. Next, use curly braces to insert a JavaScript value. Finally, keep the markup readable by breaking long lines sensibly. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Price({ amount }) {
return <p>Total: ${amount}</p>;
}
Read the example from the top down. The curly braces switch from markup back to JavaScript, so amount is inserted as a live value rather than as literal text. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with JSX in components is forgetting the curly braces around a variable, which displays the variable name as text instead of its value. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What do curly braces do inside JSX?
Section 4 — Rendering a component
Rendering a component means React runs its function and turns the returned markup into real elements on the page. That definition is worth unpacking slowly, because rendering a component shows up in almost every React screen you will build. When you can say in plain words what rendering a component does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Understanding rendering helps you stop guessing: the screen is simply the latest output of your components for their current data.
Working with rendering a component usually follows a small, repeatable pattern. First, write the component function. Next, place it in another component as a tag. Finally, let React run it and display the result. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function App() {
return <Greeting />;
}
Read the example from the top down. App renders Greeting by writing it as a tag, and React takes care of calling the function and placing its output. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with rendering a component is calling a component as an ordinary function instead of writing it as a tag, which bypasses how React tracks it. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What happens when React renders a component?
Section 5 — Composing components
Composition means building a screen by placing smaller components inside larger ones, like nesting boxes inside a larger box. That definition is worth unpacking slowly, because composing components shows up in almost every React screen you will build. When you can say in plain words what composing components does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It keeps each part small and focused, while the larger component only has to decide which parts appear and in what order.
Working with composing components usually follows a small, repeatable pattern. First, build the small pieces first. Next, place them inside a parent component. Finally, check that the parent reads like an outline of the screen. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Page() {
return (
<main>
<Header />
<Article />
</main>
);
}
Read the example from the top down. Page does not contain the details of Header or Article; it only arranges them, which is exactly what a parent should do. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with composing components is putting every detail into one giant parent component instead of composing smaller, named pieces. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why is composing small components better than one giant component?
Section 6 — Props basics
Props are the inputs a component receives from its parent, passed as attributes that look like HTML attributes but carry JavaScript values. That definition is worth unpacking slowly, because props shows up in almost every React screen you will build. When you can say in plain words what props does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Props let one component serve many situations: the same Card can show different titles, texts, and images depending on what it receives.
Working with props usually follows a small, repeatable pattern. First, decide what data the child needs. Next, pass each value as an attribute on the child tag. Finally, read the value inside the child from its props. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Card({ title }) {
return <h2>{title}</h2>;
}
// <Card title="Hello" />
Read the example from the top down. Card does not invent its title; it receives it, so the same component can be reused with a different title elsewhere. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with props is expecting a child to know data that was never passed to it as a prop. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Where do props come from, and who supplies them?
Section 7 — Passing different prop types
Props can carry strings, numbers, booleans, arrays, objects, and even functions, because they are ordinary JavaScript values passed through JSX. That definition is worth unpacking slowly, because different prop types shows up in almost every React screen you will build. When you can say in plain words what different prop types does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Knowing the full range stops you from forcing everything into a string and then parsing it back, which is fragile and confusing.
Working with different prop types usually follows a small, repeatable pattern. First, pass a string in quotes for simple text. Next, pass other values inside curly braces. Finally, check the type inside the child if the output looks wrong. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Badge({ count, active }) {
return <span>{active ? count : 0}</span>;
}
Read the example from the top down. Here count is a number and active is a boolean, both passed in braces, while a plain string prop would simply use quotes. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with different prop types is passing a number as a quoted string and then being surprised when arithmetic behaves like text joining. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you pass a number prop, as opposed to a string prop?
Section 8 — Props are read-only
Props are read-only inside the receiving component, which means a child must not change the props object or the values it received. That definition is worth unpacking slowly, because read-only props shows up in almost every React screen you will build. When you can say in plain words what read-only props does, you can decide where it belongs, what data it needs, and what should happen when that data changes. This rule keeps data flow predictable: if only the owner of data can change it, you always know where a change came from.
Working with read-only props usually follows a small, repeatable pattern. First, treat every prop as input you may read. Next, ask the parent to change the value if a change is needed. Finally, pass a callback prop when the child needs to request a change. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Title({ text }) {
return <h1>{text}</h1>;
}
Read the example from the top down. Title reads text and displays it; it never assigns a new value to text, so the parent remains in control. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with read-only props is assigning a new value to a prop inside a child and wondering why the parent screen does not update consistently. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why should a child never change its own props?
Section 9 — Default prop values
A default prop value is the value a component uses when its parent does not supply that prop, written as a default in the function parameters. That definition is worth unpacking slowly, because default prop values shows up in almost every React screen you will build. When you can say in plain words what default prop values does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Defaults make components friendlier and safer, because a missing optional prop produces sensible output instead of a blank or an error.
Working with default prop values usually follows a small, repeatable pattern. First, identify which props are optional. Next, give each optional prop a sensible default. Finally, test the component with the prop omitted. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Button({ label = "Continue" }) {
return <button>{label}</button>;
}
Read the example from the top down. When no label is passed, Button shows Continue, so callers only need to pass a label when they want something different. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with default prop values is choosing a default that hides a real mistake, such as a missing title that should always have been supplied. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: When should you give a prop a default value?
Section 10 — The children prop
The children prop is a special prop that holds whatever you place between a component opening and closing tag. That definition is worth unpacking slowly, because the children prop shows up in almost every React screen you will build. When you can say in plain words what the children prop does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It lets you build wrapper components, such as a Panel or a Layout, that add structure around content they do not need to know in advance.
Working with the children prop usually follows a small, repeatable pattern. First, write a component with an opening and closing tag. Next, place content between those tags. Finally, render children inside the wrapper where the content belongs. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Panel({ children }) {
return <section>{children}</section>;
}
Read the example from the top down. Panel does not decide the content; it wraps whatever the caller placed inside it, which makes it reusable for many kinds of content. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with the children prop is forgetting to render children, so content placed inside a wrapper silently disappears. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What does the children prop contain?
Section 11 — Destructuring props
Destructuring props means pulling named values out of the props object directly in the function parameters, instead of writing props dot something each time. That definition is worth unpacking slowly, because destructuring props shows up in almost every React screen you will build. When you can say in plain words what destructuring props does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It makes a component shorter and clearer, because the values it needs are listed in one place at the top of the function.
Working with destructuring props usually follows a small, repeatable pattern. First, list the props the component needs in its parameters. Next, use those names directly in the markup. Finally, keep the list short, or split the component if it grows. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function User({ name, city }) {
return <p>{name} lives in {city}.</p>;
}
Read the example from the top down. The parameter list itself documents the component: it needs a name and a city, and nothing else. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with destructuring props is destructuring a prop that was never passed, which leaves the value undefined and produces a blank in the output. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What does destructuring props in the parameters achieve?
Section 12 — Prop drilling
Prop drilling is passing a value through several intermediate components that do not use it themselves, only to reach a deeper component that does. That definition is worth unpacking slowly, because prop drilling shows up in almost every React screen you will build. When you can say in plain words what prop drilling does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It is a useful first approach, but when many layers are involved it becomes noisy, because every middle layer must accept and forward the value.
Working with prop drilling usually follows a small, repeatable pattern. First, pass the value from the parent to the child. Next, forward it through each intermediate layer. Finally, use it only in the component that truly needs it. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function App() {
const name = "Ada";
return <Middle name={name} />;
}
Read the example from the top down. Middle receives name only to forward it onward, which is fine for one layer but tedious when the chain is long. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with prop drilling is drilling a value through many layers when a shared context or a restructured layout would be simpler. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What is prop drilling, and when does it become a problem?
Section 13 — Reusing components with props
A reusable component is one written once and used in many places, with props supplying the differences between each use. That definition is worth unpacking slowly, because reusing components with props shows up in almost every React screen you will build. When you can say in plain words what reusing components with props does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Reuse saves effort and keeps a screen consistent, because fixing the component once fixes every place that uses it.
Working with reusing components with props usually follows a small, repeatable pattern. First, find the parts that stay the same across uses. Next, turn the parts that change into props. Finally, use the component several times with different props. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Tag({ text }) {
return <span>{text}</span>;
}
// <Tag text="New" /> <Tag text="Sale" />
Read the example from the top down. Both Tags share the same shape, but their text differs, so one component serves two purposes without duplication. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with reusing components with props is copying and pasting a whole component to change one word, instead of turning that word into a prop. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What should become a prop when you make a component reusable?
Section 14 — Conditional rendering with props
Conditional rendering means showing different markup depending on a value, often a boolean prop that says whether something applies. That definition is worth unpacking slowly, because conditional rendering with props shows up in almost every React screen you will build. When you can say in plain words what conditional rendering with props does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It lets one component handle several states, such as logged in or logged out, without duplicating the whole screen.
Working with conditional rendering with props usually follows a small, repeatable pattern. First, decide which condition controls the output. Next, write the markup for each case. Finally, use a ternary or a short-circuit expression to choose. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Status({ online }) {
return <p>{online ? "Online" : "Offline"}</p>;
}
Read the example from the top down. The ternary reads as a question: if online, show Online, otherwise show Offline, and nothing else needs to change. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with conditional rendering with props is returning nothing silently when a condition is false, instead of showing a clear empty or offline message. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How does a boolean prop change what a component renders?
Section 15 — Lists and keys
When you render a list from an array, React needs a key on each item, a stable identifier that tells it which item is which across renders. That definition is worth unpacking slowly, because lists and keys shows up in almost every React screen you will build. When you can say in plain words what lists and keys does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Keys let React update, reorder, and remove the right items efficiently, instead of rebuilding the whole list or confusing one item with another.
Working with lists and keys usually follows a small, repeatable pattern. First, map over the array to produce elements. Next, give each element a key from a stable id. Finally, avoid using the array index as a key when order can change. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function List({ items }) {
return <ul>{items.map(i => <li key={i.id}>{i.name}</li>)}</ul>;
}
Read the example from the top down. Each list item uses its own id as its key, so React can track it even if the list is reordered or filtered. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with lists and keys is using the array index as a key for a list that can be reordered, which can mix up item state. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why does each item in a rendered list need a key?
Section 16 — Component files and organisation
Organising components means giving each component its own file, with a clear name, and importing it where it is used. That definition is worth unpacking slowly, because component files and organisation shows up in almost every React screen you will build. When you can say in plain words what component files and organisation does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Small files are easier to find, read, and change than one enormous file, especially when a project grows beyond a few screens.
Working with component files and organisation usually follows a small, repeatable pattern. First, create one file per component. Next, name the file after the component. Finally, import the component at the top of the file that uses it. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
import Card from "./Card";
function App() {
return <Card title="Hi" />;
}
Read the example from the top down. The import line states the dependency plainly, so a reader can see at a glance where Card comes from. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with component files and organisation is putting dozens of unrelated components in one file, so finding and fixing one becomes a hunt. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why give each component its own file?
Section 17 — Naming components
Naming a component well means choosing a capitalised, specific name that says what the component is or does, not how it looks in one place. That definition is worth unpacking slowly, because naming components shows up in almost every React screen you will build. When you can say in plain words what naming components does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Good names act as documentation: a reader can guess a component purpose from its name before opening its file.
Working with naming components usually follows a small, repeatable pattern. First, describe the job, not the styling. Next, use a capital letter at the start. Finally, avoid vague names like Box or Thing when a clearer name exists. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function CheckoutButton() {
return <button>Checkout</button>;
}
Read the example from the top down. CheckoutButton tells you its job immediately, while a name like Button alone would hide that purpose. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with naming components is naming a component after its colour or size, which breaks the moment the design changes. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What makes a component name good?
Section 18 — JSX expressions in components
A JSX expression is any JavaScript value or calculation placed inside curly braces in markup, evaluated when the component renders. That definition is worth unpacking slowly, because JSX expressions in components shows up in almost every React screen you will build. When you can say in plain words what JSX expressions in components does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Expressions let markup stay dynamic: totals, names, and counts update automatically when the underlying values change.
Working with JSX expressions in components usually follows a small, repeatable pattern. First, write the calculation inside curly braces. Next, keep the expression short and readable. Finally, move a long calculation into a named variable above the return. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Total({ price, qty }) {
return <p>{price * qty}</p>;
}
Read the example from the top down. The total is calculated at render time, so it always reflects the current price and quantity without extra work. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with JSX expressions in components is putting a long, tangled calculation directly in JSX, where it is hard to read and harder to debug. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Where in JSX do you write a JavaScript expression?
Section 19 — Component return rules and fragments
A component must return a single root element, and a fragment lets you group several elements without adding an extra element to the page. That definition is worth unpacking slowly, because fragments and return rules shows up in almost every React screen you will build. When you can say in plain words what fragments and return rules does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Fragments keep the page structure clean when a wrapper div would change layout or add unwanted nesting.
Working with fragments and return rules usually follows a small, repeatable pattern. First, decide what the component should return. Next, wrap multiple siblings in a fragment if no wrapper is needed. Finally, use a real element only when the wrapper itself has a purpose. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Pair() {
return (<><h1>Title</h1><p>Body</p></>);
}
Read the example from the top down. The empty angle brackets are a fragment: they group the heading and paragraph without adding a div around them. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with fragments and return rules is adding unnecessary wrapper divs everywhere, which can disturb layout and make the markup harder to read. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What problem does a fragment solve?
Section 20 — What state is
State is data that a component remembers between renders and can change over time, such as whether a menu is open or what a user typed. That definition is worth unpacking slowly, because state shows up in almost every React screen you will build. When you can say in plain words what state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Without state, a component would forget everything on every render; with it, the interface can respond to people and remember their actions.
Working with state usually follows a small, repeatable pattern. First, identify data that changes while the screen is open. Next, store it with a state hook rather than a plain variable. Finally, let React re-render when that data changes. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const [open, setOpen] = useState(false);
Read the example from the top down. Here open remembers whether something is open, and setOpen is the only intended way to change that memory. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with state is storing changing interface data in a plain variable, which React will not track and will lose on re-render. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: In plain words, what is state?
Section 21 — useState basics
The useState hook gives a component a piece of state and a function to update it, returning them as a pair in an array. That definition is worth unpacking slowly, because useState shows up in almost every React screen you will build. When you can say in plain words what useState does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It is the simplest way to make a component remember something, and most interactive components start with exactly this pattern.
Working with useState usually follows a small, repeatable pattern. First, call useState with an initial value. Next, store the returned pair in variables. Finally, display the state value in the markup. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const [count, setCount] = useState(0);
return <p>{count}</p>;
Read the example from the top down. The pair is usually destructured into a value and a setter whose name starts with set, which makes the pattern easy to recognise. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with useState is calling useState outside a component or inside a condition, which breaks the rules hooks depend on. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What two things does useState return?
Section 22 — Updating state
Updating state means calling the setter function with a new value, after which React schedules a re-render showing the new value. That definition is worth unpacking slowly, because updating state shows up in almost every React screen you will build. When you can say in plain words what updating state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. You never assign directly to the state variable, because React only notices a change when it goes through the setter.
Working with updating state usually follows a small, repeatable pattern. First, work out the new value. Next, call the setter with that value. Finally, let React re-render and display the result. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>Add</button>;
}
Read the example from the top down. Clicking calls setN with the next number, and React then re-renders the button area with the updated count. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with updating state is writing count equals count plus one instead of calling the setter, so the screen never updates. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you correctly update a state value?
Section 23 — State versus plain variables
A plain variable is recreated on every render and forgotten, while state survives between renders and triggers a new render when it changes. That definition is worth unpacking slowly, because state versus plain variables shows up in almost every React screen you will build. When you can say in plain words what state versus plain variables does, you can decide where it belongs, what data it needs, and what should happen when that data changes. This distinction explains many beginner surprises: a variable that seems to update in code but never changes on screen was never state.
Working with state versus plain variables usually follows a small, repeatable pattern. First, ask whether the value must survive a re-render. Next, ask whether changing it should update the screen. Finally, use state when either answer is yes. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
let total = 0;
// total changes here will not re-render
Read the example from the top down. A plain variable like total can be useful for a temporary calculation, but it cannot drive what the user sees over time. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with state versus plain variables is using a plain variable for a value the screen must show, then wondering why the display stays stale. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why does a plain variable not update the screen like state does?
Section 24 — Multiple state values
A component can hold several independent pieces of state, each with its own useState call, for data that changes independently. That definition is worth unpacking slowly, because multiple state values shows up in almost every React screen you will build. When you can say in plain words what multiple state values does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Separate state values keep updates simple: changing one does not force you to rebuild an object containing everything else.
Working with multiple state values usually follows a small, repeatable pattern. First, list the independent values the component tracks. Next, give each one its own useState call. Finally, update only the value that actually changed. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const [name, setName] = useState("");
const [age, setAge] = useState(0);
Read the example from the top down. Name and age change independently, so keeping them separate avoids touching age when only the name changes. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with multiple state values is cramming unrelated values into one object, then writing awkward updates that copy everything else. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: When should you use separate useState calls?
Section 25 — State and re-rendering
When state changes, React re-renders the component, running its function again with the new state value and updating the screen to match. That definition is worth unpacking slowly, because state and re-rendering shows up in almost every React screen you will build. When you can say in plain words what state and re-rendering does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Re-rendering is not wasteful in the way beginners fear: React compares the new output with the old and updates only what changed in the page.
Working with state and re-rendering usually follows a small, repeatable pattern. First, change state through its setter. Next, let React run the component again. Finally, trust React to update only the changed parts of the page. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
setCount(5); // triggers a re-render
Read the example from the top down. After setCount runs, the component function runs again with the new count, and the displayed number changes to match. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with state and re-rendering is assuming a re-render rebuilds the whole page from scratch, and avoiding state updates out of misplaced fear. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What triggers a re-render, and what does React do then?
Section 26 — Event handlers that update state
An event handler is a function that runs when a user acts, such as clicking a button, and it often updates state to reflect that action. That definition is worth unpacking slowly, because event handlers updating state shows up in almost every React screen you will build. When you can say in plain words what event handlers updating state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Handlers connect human actions to state changes, which is how a static display becomes an interactive interface.
Working with event handlers updating state usually follows a small, repeatable pattern. First, attach the handler to the event, such as onClick. Next, inside the handler, work out the new state. Finally, call the setter and let React re-render. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Toggle() {
const [on, setOn] = useState(false);
return <button onClick={() => setOn(!on)}>Toggle</button>;
}
Read the example from the top down. Each click flips on to its opposite, so the button text or display can follow the current state. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with event handlers updating state is calling the handler immediately during rendering instead of passing it as a function to run on the event. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What is the job of an event handler that updates state?
Section 27 — Controlled inputs
A controlled input is a form field whose displayed value comes from state, and whose changes update that state through an onChange handler. That definition is worth unpacking slowly, because controlled inputs shows up in almost every React screen you will build. When you can say in plain words what controlled inputs does, you can decide where it belongs, what data it needs, and what should happen when that data changes. This gives the component full control: it can validate, format, or block input as the user types, because every keystroke passes through state.
Working with controlled inputs usually follows a small, repeatable pattern. First, store the field value in state. Next, set the input value to that state. Finally, update state in onChange from the event target value. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function NameInput() {
const [name, setName] = useState("");
return <input value={name} onChange={e => setName(e.target.value)} />;
}
Read the example from the top down. The input shows exactly what state holds, and typing updates state, so the two can never drift apart. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with controlled inputs is setting value without onChange, which freezes the input so the user cannot type at all. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What makes an input controlled?
Section 28 — Lifting state up
Lifting state up means moving state from a child into their nearest shared parent, so several children can read or change the same value. That definition is worth unpacking slowly, because lifting state up shows up in almost every React screen you will build. When you can say in plain words what lifting state up does, you can decide where it belongs, what data it needs, and what should happen when that data changes. It is the standard fix when two components must stay in sync: instead of each keeping its own copy, they share one source of truth.
Working with lifting state up usually follows a small, repeatable pattern. First, find the components that must agree. Next, move the state to their nearest common parent. Finally, pass the value and the setter down as props. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Parent() {
const [text, setText] = useState("");
return <Child text={text} onChange={setText} />;
}
Read the example from the top down. Parent owns text, and Child receives it, so any sibling added later can read the same value from the same owner. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with lifting state up is keeping separate copies of the same value in two components, which then drift out of sync. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: When should you lift state up to a parent?
Section 29 — State in parent versus child
Deciding where state lives means asking which component needs the value, and placing state at the lowest common owner of all of them. That definition is worth unpacking slowly, because parent versus child state shows up in almost every React screen you will build. When you can say in plain words what parent versus child state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. State placed too high forces unrelated components to re-render and pass props they do not need, while state placed too low cannot be shared.
Working with parent versus child state usually follows a small, repeatable pattern. First, list every component that reads the value. Next, list every component that changes it. Finally, place state in their nearest shared parent, and no higher. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Parent() {
const [tab, setTab] = useState("home");
return <Tabs tab={tab} onTab={setTab} />;
}
Read the example from the top down. Tab state lives in Parent because Parent and Tabs both care about it, but it does not need to live higher than that. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with parent versus child state is lifting every piece of state to the top of the app by default, which turns the top component into a dumping ground. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you decide where state should live?
Section 30 — Passing setters as props
Passing a setter as a prop means giving a child the function that updates a parent state value, so the child can request a change without owning the data. That definition is worth unpacking slowly, because passing setters as props shows up in almost every React screen you will build. When you can say in plain words what passing setters as props does, you can decide where it belongs, what data it needs, and what should happen when that data changes. This keeps ownership in one place while still letting children act: the child asks, the parent decides, and React updates everyone.
Working with passing setters as props usually follows a small, repeatable pattern. First, keep the state in the parent. Next, pass the setter down as a named prop. Finally, call that prop from the child event handler. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Child({ onAdd }) {
return <button onClick={onAdd}>Add</button>;
}
Read the example from the top down. Child does not know how the parent stores the value; it only knows to call onAdd when the button is clicked. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with passing setters as props is passing the state value but not the setter, then wondering why a child button cannot change anything. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why pass a setter down, rather than letting the child own the state?
Section 31 — State initial values and lazy initialisation
A state initial value is the value used on the first render, and lazy initialisation means passing a function so an expensive initial value is computed only once. That definition is worth unpacking slowly, because lazy state initialisation shows up in almost every React screen you will build. When you can say in plain words what lazy state initialisation does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Lazy initialisation matters when computing the starting value takes noticeable work, because otherwise that work would repeat on every render.
Working with lazy state initialisation usually follows a small, repeatable pattern. First, choose a simple initial value when you can. Next, pass a function to useState for an expensive one. Finally, remember the function runs only on the first render. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const [items, setItems] = useState(() => buildItems());
Read the example from the top down. The arrow function runs once to build the initial items, and later renders reuse the stored state instead of rebuilding. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with lazy state initialisation is computing an expensive initial value directly on every render, or expecting the lazy function to run again later. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: When should you pass a function to useState?
Section 32 — Updating state from previous state
When a new state value depends on the old one, pass a function to the setter that receives the previous value and returns the next one. That definition is worth unpacking slowly, because updating from previous state shows up in almost every React screen you will build. When you can say in plain words what updating from previous state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. This avoids stale values when several updates happen close together, because each update works from the latest value rather than an old snapshot.
Working with updating from previous state usually follows a small, repeatable pattern. First, identify that the new value depends on the old. Next, pass an updater function to the setter. Finally, return the new value from that function. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
setCount(prev => prev + 1);
Read the example from the top down. Even if several increments are queued, each one receives the previous count and adds one, so none is lost. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with updating from previous state is using the old state variable directly inside several rapid updates, which can lose some of those updates. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why pass a function to a setter when the new value depends on the old?
Section 33 — State objects
State can hold an object, but you must replace it with a new object when you update it, rather than changing a property of the existing object. That definition is worth unpacking slowly, because state objects shows up in almost every React screen you will build. When you can say in plain words what state objects does, you can decide where it belongs, what data it needs, and what should happen when that data changes. React detects a change by comparing references, so mutating the old object in place looks like no change at all and may not re-render.
Working with state objects usually follows a small, repeatable pattern. First, spread the old object into a new one. Next, override only the property that changed. Finally, pass the new object to the setter. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
setUser(prev => ({ ...prev, name: "Ada" }));
Read the example from the top down. The spread copies every existing property, then name is replaced, producing a fresh object that React recognises as changed. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with state objects is mutating a state object directly, such as assigning to one of its properties, and expecting a re-render. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you correctly update one property of a state object?
Section 34 — State arrays and immutable updates
Updating a state array means creating a new array with the change applied, using methods that return a new array rather than changing the old one. That definition is worth unpacking slowly, because immutable array updates shows up in almost every React screen you will build. When you can say in plain words what immutable array updates does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Immutability keeps renders predictable and makes it easy to compare old and new lists, which React and debugging tools both rely on.
Working with immutable array updates usually follows a small, repeatable pattern. First, to add, spread the old array plus the new item. Next, to remove, filter out the unwanted item. Finally, to change one item, map and replace only that item. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
setItems(prev => prev.filter(i => i.id !== 2));
Read the example from the top down. Filtering returns a new array without the removed item, while the original array is left untouched. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with immutable array updates is pushing into a state array directly, which mutates it and may not trigger a visible update. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you remove an item from a state array correctly?
Section 35 — Keeping state minimal and derived values
A derived value is one you can calculate from existing state during rendering, so it should not be stored as separate state. That definition is worth unpacking slowly, because derived values shows up in almost every React screen you will build. When you can say in plain words what derived values does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Keeping state minimal reduces bugs, because there is only one source of truth and no second copy that can drift out of sync.
Working with derived values usually follows a small, repeatable pattern. First, list the values your component stores. Next, ask whether each can be calculated from the others. Finally, calculate derived values in the body instead of storing them. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const total = items.length;
return <p>{total} items</p>;
Read the example from the top down. Total is derived from items on every render, so it can never disagree with the list it counts. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with derived values is storing a count alongside a list, then forgetting to update the count when the list changes. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: When should a value be calculated rather than stored as state?
Section 36 — Component identity and state preservation
React keeps a component state as long as that component stays in the same position in the tree; moving it or changing its type resets its state. That definition is worth unpacking slowly, because component identity and state shows up in almost every React screen you will build. When you can say in plain words what component identity and state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. This explains why a form can lose its input when a wrapper changes: React sees a different component in that spot and starts fresh.
Working with component identity and state usually follows a small, repeatable pattern. First, keep a component in the same position when its state matters. Next, avoid defining components inside other components. Finally, use a stable key when a list item identity must persist. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function App() {
return show ? <Form /> : <Other />;
}
Read the example from the top down. If Form is removed and later returned, its state starts again, because React treats the returning component as new in that position. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with component identity and state is defining a component inside another component, which recreates it on every render and resets its state. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What determines whether a component keeps its state?
Section 37 — State and side effects boundary
State describes what the screen should show, while a side effect is work outside rendering, such as fetching data or touching the browser directly. That definition is worth unpacking slowly, because state and side effects shows up in almost every React screen you will build. When you can say in plain words what state and side effects does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Keeping the boundary clear stops rendering from doing unpredictable work, because rendering should be a pure calculation from props and state.
Working with state and side effects usually follows a small, repeatable pattern. First, compute the display from props and state during rendering. Next, put outside work in event handlers or effects. Finally, never change outside state during the render itself. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Display({ name }) {
return <p>{name}</p>;
}
Read the example from the top down. Display only calculates markup from name; it does not fetch, write, or change anything else while rendering. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with state and side effects is fetching data or writing to storage directly during rendering, which can run repeatedly and unpredictably. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What belongs in rendering, and what belongs outside it?
Section 38 — Forms with a single state object
A form with several fields can store all its values in one state object, updating one field at a time while spreading the rest unchanged. That definition is worth unpacking slowly, because forms with one state object shows up in almost every React screen you will build. When you can say in plain words what forms with one state object does, you can decide where it belongs, what data it needs, and what should happen when that data changes. One object keeps related fields together and makes submitting the whole form a single, simple step.
Working with forms with one state object usually follows a small, repeatable pattern. First, create one state object with a key per field. Next, give each input a name matching its key. Finally, update only the changed key on each change. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const [form, setForm] = useState({ name: "", email: "" });
setForm(prev => ({ ...prev, name: "Ada" }));
Read the example from the top down. Updating name spreads the existing email unchanged, so the object always holds the full form, not just the last field. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with forms with one state object is replacing the whole form object with only the changed field, which wipes out the other fields. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you update one field in a single-object form state?
Section 39 — Toggling interface with state
Toggling means switching a boolean state between true and false, often to show or hide a menu, panel, or detail section. That definition is worth unpacking slowly, because toggling with state shows up in almost every React screen you will build. When you can say in plain words what toggling with state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. A boolean is the simplest state shape for an on-or-off interface element, and it makes the intent obvious to any reader.
Working with toggling with state usually follows a small, repeatable pattern. First, store the open or closed value as a boolean. Next, flip it in the click handler. Finally, render different markup for each value. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const [open, setOpen] = useState(false);
<button onClick={() => setOpen(!open)}>Menu</button>
Read the example from the top down. Each click flips open, and the menu markup can follow that single boolean without extra bookkeeping. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with toggling with state is storing open and closed as two separate booleans that can contradict each other. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you toggle a menu open and closed with state?
Section 40 — Counters tabs and accordions
Counters, tabs, and accordions are classic state patterns: a number that increments, a selected tab name, and an open section identifier. That definition is worth unpacking slowly, because common state patterns shows up in almost every React screen you will build. When you can say in plain words what common state patterns does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Learning these three patterns gives you a toolkit for most simple interactive widgets, because many interfaces are variations on them.
Working with common state patterns usually follows a small, repeatable pattern. First, for a counter, store a number. Next, for tabs, store the selected tab id. Finally, for an accordion, store the open section id or none. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
const [tab, setTab] = useState("home");
return <p>Showing {tab}</p>;
Read the example from the top down. Tab state is just a string naming the active tab, and the display follows it, which keeps the pattern small and clear. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with common state patterns is storing a separate boolean for every tab, which lets several tabs claim to be active at once. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What single value can represent the selected tab?
Section 41 — Props versus state decision guide
Choose props when a parent supplies data or a child only displays it, and choose state when a component itself owns data that changes over time. That definition is worth unpacking slowly, because props versus state shows up in almost every React screen you will build. When you can say in plain words what props versus state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. This decision is the most common design question in React, and answering it early prevents tangled data flow later.
Working with props versus state usually follows a small, repeatable pattern. First, ask who owns the data. Next, ask who changes it and when. Finally, use props for supplied data and state for owned, changing data. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Card({ title }) {
const [liked, setLiked] = useState(false);
return <h2>{title}</h2>;
}
Read the example from the top down. Title arrives as a prop because the parent owns it, while liked is state because this card owns its own like status. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with props versus state is storing a prop value in state and then never updating it, so the component ignores later prop changes. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you decide between props and state for a value?
Section 42 — Debugging props and state
Debugging props and state means checking the actual values at each step, rather than guessing what a component received. That definition is worth unpacking slowly, because debugging props and state shows up in almost every React screen you will build. When you can say in plain words what debugging props and state does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Most display bugs are data bugs, so seeing the real value quickly points to the step where it went wrong.
Working with debugging props and state usually follows a small, repeatable pattern. First, log the prop or state value inside the component. Next, compare it with the value the parent intended to pass. Finally, trace it back one step at a time to its owner. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
console.log("title:", title);
Read the example from the top down. A single log line showing the real title often reveals a typo, a missing prop, or a value that was never updated. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with debugging props and state is changing code at random before checking what value the component actually received. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What should you check first when a component shows the wrong value?
Section 43 — Prop validation mindset
Prop validation is the habit of stating what props a component expects, their types, and which are required, and checking that callers meet that contract. That definition is worth unpacking slowly, because prop validation mindset shows up in almost every React screen you will build. When you can say in plain words what prop validation mindset does, you can decide where it belongs, what data it needs, and what should happen when that data changes. A clear contract catches mistakes early: a missing required prop or a wrong type becomes a visible warning instead of a silent blank.
Working with prop validation mindset usually follows a small, repeatable pattern. First, list each prop the component needs. Next, note its type and whether it is required. Finally, check callers against that list when something looks wrong. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Avatar({ name, size = 40 }) {
return <span>{name}</span>;
}
Read the example from the top down. Avatar expects a name and an optional size, and a reader can see that contract in the parameters without hunting through the file. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with prop validation mindset is accepting any prop silently and discovering only later that a caller passed the wrong type. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why state what props a component expects?
Section 44 — Pure components
A pure component returns the same output for the same props and state, without changing anything outside itself during rendering. That definition is worth unpacking slowly, because pure components shows up in almost every React screen you will build. When you can say in plain words what pure components does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Purity makes components predictable and testable, because the same inputs always lead to the same screen.
Working with pure components usually follows a small, repeatable pattern. First, base the output only on props and state. Next, avoid changing outside variables during rendering. Finally, move outside work into handlers or effects. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Double({ n }) {
return <p>{n * 2}</p>;
}
Read the example from the top down. Double always shows twice its input, and nothing else in the app changes because Double rendered. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with pure components is reading a changing outside variable during rendering, so the same props sometimes produce different output. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What does it mean for a component to be pure?
Section 45 — Composition versus inheritance
Composition builds new components by combining existing ones, while inheritance would build them by extending a parent class, and React favours composition. That definition is worth unpacking slowly, because composition versus inheritance shows up in almost every React screen you will build. When you can say in plain words what composition versus inheritance does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Composition is more flexible, because you can mix and match pieces without being locked into one rigid family tree.
Working with composition versus inheritance usually follows a small, repeatable pattern. First, build small, focused components. Next, combine them inside a parent. Finally, use children or props to vary the combined result. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Layout({ children }) {
return <div>{children}</div>;
}
Read the example from the top down. Layout composes whatever children it receives, instead of forcing every page to inherit from one fixed layout class. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with composition versus inheritance is trying to extend components through inheritance, which React does not encourage and which quickly becomes rigid. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Why does React favour composition over inheritance?
Section 46 — Splitting large components
Splitting a large component means extracting a coherent piece of markup and logic into its own named component. That definition is worth unpacking slowly, because splitting large components shows up in almost every React screen you will build. When you can say in plain words what splitting large components does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Smaller components are easier to understand, test, and reuse, and the parent becomes an outline rather than a wall of markup.
Working with splitting large components usually follows a small, repeatable pattern. First, find a section with one clear job. Next, move it into its own component with props for its data. Finally, replace the original section with the new component tag. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Header() {
return <header>Site name</header>;
}
Read the example from the top down. Once Header exists, the parent no longer carries header details, and Header can be reused or changed in one place. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with splitting large components is splitting by line count alone, which can create meaningless pieces instead of pieces with a clear job. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: How do you know where to split a large component?
Section 47 — Presentational and container thinking
Presentational thinking separates components that display data from components that manage data and logic, even when both live in the same file at first. That definition is worth unpacking slowly, because presentational and container thinking shows up in almost every React screen you will build. When you can say in plain words what presentational and container thinking does, you can decide where it belongs, what data it needs, and what should happen when that data changes. The separation makes display pieces easy to reuse with different data, while logic pieces can change without restyling everything.
Working with presentational and container thinking usually follows a small, repeatable pattern. First, identify which parts only display. Next, identify which parts fetch or manage state. Finally, keep display parts focused on markup and props. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function ListView({ items }) {
return <ul>{items.map(i => <li key={i.id}>{i.name}</li>)}</ul>;
}
Read the example from the top down. ListView only displays items; it does not care where they came from, so it can be reused with any list. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with presentational and container thinking is mixing fetching, state, and markup in every component, so nothing can be reused without dragging its logic along. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What is the benefit of separating display from data management?
Section 48 — Reusable button card and input components
Reusable button, card, and input components are small building blocks whose differences are supplied as props, such as label, title, or value. That definition is worth unpacking slowly, because reusable button card input shows up in almost every React screen you will build. When you can say in plain words what reusable button card input does, you can decide where it belongs, what data it needs, and what should happen when that data changes. A shared set of building blocks keeps an app consistent, because every button and card follows the same shape and behaviour.
Working with reusable button card input usually follows a small, repeatable pattern. First, design the shared shape once. Next, turn differences into props. Finally, use the block everywhere instead of rebuilding it. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function MyButton({ label, onClick }) {
return <button onClick={onClick}>{label}</button>;
}
Read the example from the top down. MyButton works for any label and any click action, so a new button is one line, not a new component. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with reusable button card input is creating a slightly different button for every screen, so the app slowly drifts into many inconsistent styles. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: What makes a button component reusable?
Section 49 — Common component mistakes
Common component mistakes include forgetting keys, mutating props or state, and storing derived values as separate state. That definition is worth unpacking slowly, because common component mistakes shows up in almost every React screen you will build. When you can say in plain words what common component mistakes does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Naming these mistakes in advance helps you recognise them in your own code, because each one produces a familiar symptom.
Working with common component mistakes usually follows a small, repeatable pattern. First, check keys when a list behaves oddly. Next, check mutation when an update does not appear. Finally, check derived state when two values disagree. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function Item({ item }) {
return <li key={item.id}>{item.name}</li>;
}
Read the example from the top down. Even in a tiny example, the key, the read-only prop, and the derived display all follow the rules that prevent the common mistakes. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with common component mistakes is fixing a symptom, such as forcing a re-render, instead of fixing the underlying mutation or missing key. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: Name three common component mistakes and their fixes.
Section 50 — Putting components props and state together
A small complete example ties the chapter together: a parent owns a list, passes items as props, and each item uses state for its own liked status. That definition is worth unpacking slowly, because components props and state together shows up in almost every React screen you will build. When you can say in plain words what components props and state together does, you can decide where it belongs, what data it needs, and what should happen when that data changes. Seeing the three ideas in one place shows how they divide labour: the parent owns shared data, props carry it down, and state handles local interaction.
Working with components props and state together usually follows a small, repeatable pattern. First, let the parent own the shared list. Next, pass each item down as props. Finally, let each item own only its local interaction state. None of these steps is complicated on its own, and that is the point: React rewards small, predictable steps repeated consistently. If a step feels mysterious, slow down and name the data involved, the component that owns it, and the moment it changes. That habit turns a confusing screen into a short list of decisions you can check one at a time, instead of a large puzzle you must solve all at once.
Here is a short example you can read line by line:
function App() {
const [items] = useState([{ id: 1, name: "Pen" }]);
return <ul>{items.map(i => <Item key={i.id} name={i.name} />)}</ul>;
}
Read the example from the top down. App owns the list, Item receives a name as a prop, and Item could add its own liked state without affecting its siblings. Notice what is fixed and what varies: the fixed parts give the component its shape, while the varying parts come from props, state, or a value calculated during rendering. Try changing one varying value in your head and predicting the new output before you run anything. If your prediction is wrong, that mismatch is useful information, because it shows exactly which part of your mental model needs fixing. Developers who predict before they run learn faster than developers who change code at random and hope the result improves.
A common mistake with components props and state together is putting all interaction state in the parent, even when only one item cares about it. The fix is usually boring in a good way: go back to the definition, check the data flowing in, and confirm that each value has one clear owner. Ask yourself three questions before you change code: what should this show, where does that value come from, and what event should change it? If you cannot answer all three, you have found the gap.
To check your own work, build the smallest version that could possibly work, run it, and compare what you see with what you expected. If it matches, add one more feature and check again. If it does not match, look at the data first: log the value, read it carefully, and ask whether it is the value you intended.
Check: In the final example, who owns the list, and who owns a single item liked status?
Practical task
Build a small contacts app: a parent component holds a list of at least four contacts in state, renders a reusable ContactCard for each one with name and city as props, and lets each card toggle a show details section with its own local state. Add a controlled input that filters the list by name, using state lifted to the parent, and check that filtering, toggling, and the list keys all behave correctly when you add or remove a contact in code.
Chapter questions
- Explain the difference between props and state, with an example of each.
- Why must props be treated as read-only inside a child component?
- A list reorders incorrectly when you filter it. What is the most likely cause, and how do you fix it?
- Write a component that receives a title prop, shows it, and toggles extra text when a button is clicked.
- Two sibling components must stay in sync. Where should the shared state live, and why?