Show a part of the page only when something is true. Learn if, the ternary, && and its 0 bug, null, and why removing a component makes it forget its state.
A real app doesn’t show the same thing all the time. A message appears only when there is one. A “Log out” button appears only after you log in. Showing something only when a condition is true is called conditional rendering.
You already have most of the tools. Part 1 showed the ? : operator and a table of which values show on the page. Part 4 showed state, and that a component taken off the page forgets its state.
This part puts them together. We’ll see several ways to choose what to show. We’ll meet the 0 bug that Part 1 promised. Then we’ll see the difference between removing a component and hiding it.
Try this first
Read this code. Don’t press Run yet.
import { useState } from 'react'
export default function App() {
const [count, setCount] = useState(0)
return (
<div>
<button onClick={() => setCount(count + 1)}>Add a message</button>
<p>Mail: {count && <b>{count} new</b>}</p>
</div>
)
}
The line {count && <b>{count} new</b>} is meant to say: “if there are messages, show how many”. When count is 0, there are no messages.
Make a guess. Before you click anything, what does the line after “Mail:” show?
Press Run.
It shows Mail: 0. We wanted nothing there, but React put a 0 on the page. Click the button, and it shows “Mail: 1 new”, as planned.
We’ll see exactly why the 0 appears, and three ways to fix it. First, a way you already know from JavaScript.
Choose with if, before the return
A component is a JavaScript function. So it can use a normal if statement, before it returns its JSX.
import { useState } from 'react'
function Inbox({ count }: { count: number }) {
if (count === 0) {
return <p>No new messages.</p>
}
return <p>New messages: {count}</p>
}
export default function App() {
const [count, setCount] = useState(0)
return (
<div>
<button onClick={() => setCount(count + 1)}>Add a message</button>
<Inbox count={count} />
</div>
)
}
Run it. At first it says “No new messages.” Click the button, and it says “New messages: 1”.
When count is 0, the function returns early, at the first return. The code after it never runs. This is called an early return. It is a good choice when the two cases look very different.
You can also use if to fill a variable, then put the variable in your JSX:
function Inbox({ count }: { count: number }) {
let message
if (count === 0) {
message = <p>No new messages.</p>
} else {
message = <p>New messages: {count}</p>
}
return <section>{message}</section>
}
This is useful when only one part of a bigger piece of JSX changes.
Remember from Part 1: if is a statement, not an expression. It can’t go inside { } in JSX. We’ll see what happens if you try, under Common mistakes.
Return null to show nothing
Sometimes a component should show nothing at all. Then it can return null.
import { useState } from 'react'
function Warning({ show }: { show: boolean }) {
console.log('Warning runs, show =', show)
if (!show) {
return null
}
return <p>Careful: the battery is low.</p>
}
export default function App() {
const [low, setLow] = useState(false)
return (
<div>
<button onClick={() => setLow(!low)}>Change</button>
<Warning show={low} />
</div>
)
}
Warning runs, show = false
Warning runs, show = false
!show means “not show“. It is true when show is false.
Run it. The page has only the button. Warning returned null, so React added nothing to the page for it. But look at the Console. Warning still ran. React called it, and it chose to return nothing.
Each line appears twice. That is Strict Mode, from Part 2: in development, React calls each component twice to help find bugs. We checked with Strict Mode off, and Warning ran once.
Press Change. The warning appears, and the Console shows two more lines with show = true.
React’s docs say returning null from a component “isn’t common”. It can surprise someone who uses the component and expects to see it. More often, the parent decides whether to show a child at all. The next two sections show how.
The ? : operator: one thing or the other
You met ? : in Part 1. It is called the ternary operator. a ? b : c means: if a is true, the answer is b. If not, the answer is c.
It is an expression, so it can go inside { }:
import { useState } from 'react'
export default function App() {
const [loggedIn, setLoggedIn] = useState(false)
return (
<div>
{loggedIn ? <p>Welcome back, Ana!</p> : <p>Please log in.</p>}
<button onClick={() => setLoggedIn(!loggedIn)}>
{loggedIn ? 'Log out' : 'Log in'}
</button>
</div>
)
}
Run it and press “Log in”. The text and the button’s label both change.
The second ? : chooses between two strings, not two tags. A ternary can choose any two values. You can use it in an attribute too: className={done ? 'done' : 'todo'}.
Use a ternary when you have exactly two choices. If one of the choices is “nothing”, write null there: {loggedIn ? <p>Welcome!</p> : null}. There is also a shorter way to write that, with &&.
The && operator: something or nothing
&& is JavaScript’s “and” operator. In React code, you will see it used like this:
function MailLabel({ unread }: { unread: boolean }) {
return <div>Mail {unread && <b>(new)</b>}</div>
}
It reads: “if unread is true, show (new)“. When unread is false, the page shows only “Mail”.
To understand the 0 bug, we need to know what && really gives back. It is not always true or false.
a && b looks at a first.
- If
acounts as false, the answer isaitself. JavaScript doesn’t even look atb. - If
acounts as true, the answer isb.
We checked in JavaScript: 5 && 'x' gives 'x'. null && 'x' gives null. And 0 && 'x' gives 0, not false.
Values that count as false
“Counts as false” has a name. A value that counts as false is called falsy. Every other value is truthy: it counts as true.
There are only a few falsy values. MDN is a set of web guides that many developers use, and it lists them. MDN’s list has one more, document.all, an old browser feature you won’t need. Here are the others, with what React showed for <p>{value && <b>yes</b>}</p>. We ran each one in React 19.3.
Value on the left of && |
Falsy? | What the page shows |
|---|---|---|
false |
yes | nothing |
null |
yes | nothing |
undefined |
yes | nothing |
'' (empty text) |
yes | nothing |
0 |
yes | 0 |
-0 |
yes | 0 |
0n (a “big” whole number) |
yes | 0 |
NaN (“not a number”) |
yes | NaN |
true, 1, '0', ' ', [], {} |
no | yes |
Look at the last row. The text '0' is truthy, because it is not empty. An empty array [] and an empty object {} are truthy too. That surprises many people.
Now look at the middle rows. These falsy values are numbers. React shows numbers, even zero. That matches Part 1’s table: {0} shows 0, and {NaN} shows NaN. For NaN, React also printed this warning in the Console:
Received NaN for the `children` attribute. If this is expected, cast the value to a string.
The 0 bug
Now “Try this first” makes sense. When count is 0, count && <b>…</b> gives back 0. The answer is a number, so React shows it.
React’s docs give the rule plainly: “Don’t put numbers on the left side of &&”. TypeScript doesn’t catch this. We checked: the “Try this first” code passes TypeScript’s checks. A number is something React can show, so TypeScript sees no error.
The fix is to make the left side a real true or false. Here are three ways. We tried each one with count at 0 and at 2:
| Code | count is 0 |
count is 2 |
|---|---|---|
{count && <b>{count} new</b>} |
0 |
2 new |
{count > 0 && <b>{count} new</b>} |
nothing | 2 new |
{Boolean(count) && <b>{count} new</b>} |
nothing | 2 new |
{count > 0 ? <b>{count} new</b> : null} |
nothing | 2 new |
count > 0 is a comparison, so its answer is always true or false. Boolean(count) turns any value into true or false. You may also see !!count. That does the same thing. One ! turns the value into true or false, but the opposite one. The second ! flips it back. It worked the same in our test.
Here is the fixed mail example:
import { useState } from 'react'
export default function App() {
const [count, setCount] = useState(0)
return (
<div>
<button onClick={() => setCount(count + 1)}>Add a message</button>
<p>Mail: {count > 0 && <b>{count} new</b>}</p>
</div>
)
}
Run it. The extra 0 is gone.
Empty text, '', is falsy too, but React shows nothing for it. So {name && <p>Hi, {name}</p>} is safe when name is text. The trouble comes only from numbers (and 0n).
Choosing between more than two
Sometimes there are more than two choices. A save button might be waiting ('idle'), loading, done, or showing an error. A ternary inside a ternary gets hard to read fast. Two clearer ways are an object that maps each choice to what to show, and a switch.
Here is the object way:
import { useState } from 'react'
type Status = 'idle' | 'loading' | 'done' | 'error'
const messages: Record<Status, string> = {
idle: 'Press a button.',
loading: 'Loading...',
done: 'Saved!',
error: 'Something went wrong.',
}
export default function App() {
const [status, setStatus] = useState<Status>('idle')
return (
<div>
<p>{messages[status]}</p>
<button onClick={() => setStatus('loading')}>loading</button>
<button onClick={() => setStatus('done')}>done</button>
<button onClick={() => setStatus('error')}>error</button>
</div>
)
}
type Status = 'idle' | 'loading' | 'done' | 'error' says a status can be only one of these four strings. Record<Status, string> is TypeScript’s way to say: “an object with one key for each status, and a string for each”.
Run it and press the buttons. messages[status] looks up the text for the current status.
TypeScript helps here. If you forget one of the statuses in the object, it stops you:
type Status = 'idle' | 'loading' | 'done' | 'error'
const messages: Record<Status, string> = {
idle: 'Press a button.',
loading: 'Loading...',
done: 'Saved!',
}
The error starts with “Property ‘error’ is missing in type”. The playground doesn’t check types, so you see this only in an editor like VS Code.
The values in the object can be JSX too, not only text.
The other way is a switch statement inside a small component. A switch compares one value with several cases. It is a statement, so it goes in the function body, not inside { }:
type Status = 'idle' | 'loading' | 'done' | 'error'
function StatusMessage({ status }: { status: Status }) {
switch (status) {
case 'loading':
return <p>Loading...</p>
case 'done':
return <p>Saved!</p>
case 'error':
return <p>Something went wrong.</p>
case 'idle':
return <p>Press a button.</p>
}
}
Each status has its own case. You may also see a default: case, which runs when no other case matches. Be careful with it. If you add a new status and forget its case, default catches it quietly, and nothing warns you.
Then the parent writes <StatusMessage status={status} />. Use the object when each choice is a simple value. Use the switch when each case needs its own code.
Removing a component, or hiding it
So far, when we chose not to show something, React took it off the page. That has a cost you saw in Part 4. This is the example from Part 4:
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>
}
export default function App() {
const [show, setShow] = useState(true)
return (
<div>
<button onClick={() => setShow(!show)}>{show ? 'Hide' : 'Show'}</button>
{show && <Counter />}
</div>
)
}
Click the counter three times. Press “Hide”, then “Show”. The counter is back at 0.
When show is false, {show && <Counter />} gives false, and React shows nothing there. So React removes Counter from the page, and throws away its state. When show is true again, React makes a brand new Counter. Its useState(0) starts at 0. We checked: after “Show”, the counter’s button was a new button, not the old one.
Adding a component to the page is called mounting it. Removing it is called unmounting it.
Now change one thing. Don’t remove Counter. Hide it:
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>
}
export default function App() {
const [show, setShow] = useState(true)
return (
<div>
<button onClick={() => setShow(!show)}>{show ? 'Hide' : 'Show'}</button>
<div hidden={!show}>
<Counter />
</div>
</div>
)
}
hidden is a normal HTML attribute. It tells the browser not to show that tag or anything inside it.
Do the same thing: three clicks, “Hide”, “Show”. This time the counter still says 3.
While it was hidden, the page still had <div hidden=""><button>Count: 3</button></div>. React never removed Counter. It only changed one attribute. So Counter kept its state. We checked: after “Show”, it was the same button as before.
Step through both ways here:
Remove it, or hide it. Choose one, then press play or step through it.
In words:
- You click the counter 3 times. It shows “Count: 3”.
- You press “Hide”. Now
showisfalse. - With
&&, React takesCounteroff the page and throws away its count. Withhidden, React keepsCounterand only addshiddento the<div>. - You press “Show”. With
&&, React makes a newCounter, which starts at 0. Withhidden, React takeshiddenaway, and the counter still shows 3.
A style works the same way: style={{ display: show ? 'block' : 'none' }}. We checked it too. The count stayed at 3.
Which one to use
Remove it (&&, ? :) |
Hide it (hidden, display: none) |
|
|---|---|---|
| Its state | thrown away | kept |
| Its tags on the page | removed | still there, not seen |
| Runs when the parent runs again | no | yes |
That last row matters for speed. We counted with Strict Mode off. Pressing “Hide” made the hidden Counter run 1 time. The removed Counter ran 0 times. A hidden component is still part of the page, so React still updates it.
Removing is the usual choice. It is easier, and it costs nothing while the component is gone. Hiding is useful when it must remember its state, like a half-filled form that the user will come back to. There is one more way to keep state: keep it in the parent, which stays on the page. Practice 2 below tries it, and Part 9 explains it.
An everyday example
Removing a component is like throwing away a page of notes. When you need it again, you get a new, empty page. Hiding it is like putting the page in a drawer. It is out of sight, but everything you wrote is still on it.
The exact version
The drawer is not free. A hidden component’s tags stay on the page, and it still runs when its parent runs.
hidden has one more catch. MDN says CSS can win over it. If a style gives that tag display: block, the browser shows it, hidden or not.
Same component, same place, same state
Here is a surprise. Read this code and guess what happens.
import { useState } from 'react'
function Counter({ label }: { label: string }) {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{label}: {count}</button>
}
export default function App() {
const [isAna, setIsAna] = useState(true)
return (
<div>
<button onClick={() => setIsAna(!isAna)}>Switch</button>
{isAna ? <Counter label="Ana" /> : <Counter label="Ben" />}
</div>
)
}
Click “Ana” three times. Then press “Switch”. It says “Ben: 3”. Ben got Ana’s count!
The two branches of the ternary look like two different counters. But React doesn’t see your if or your ? :. It sees only what your component returns. Both times, that is a Counter in the same place, right after the “Switch” button. So React thinks it is the same counter, whose label prop changed. It keeps the state.
React’s docs say state is kept while you render “the same component at the same position in the tree”. The tree is how React sees your app: components inside components, like branches on a tree.
You saw in Part 4 that a new key makes state start over. It works here too. To tell React they are different counters, give each one a key:
import { useState } from 'react'
function Counter({ label }: { label: string }) {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{label}: {count}</button>
}
export default function App() {
const [isAna, setIsAna] = useState(true)
return (
<div>
<button onClick={() => setIsAna(!isAna)}>Switch</button>
{isAna ? <Counter key="ana" label="Ana" /> : <Counter key="ben" label="Ben" />}
</div>
)
}
Now “Switch” shows “Ben: 0”. A different key means a different component to React. So React removes Ana’s counter, state and all, and makes a new one for Ben. Switch back, and Ana is at 0 too.
There is another way to get the same result. Put the two counters in two different places, with two &&s:
import { useState } from 'react'
function Counter({ label }: { label: string }) {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{label}: {count}</button>
}
function Pair({ isAna }: { isAna: boolean }) {
return (
<div>
{isAna && <Counter label="Ana" />}
{!isAna && <Counter label="Ben" />}
</div>
)
}
Each { } is its own place, even when it shows nothing. We tried it: after three clicks on Ana and a switch, Ben started at 0.
key comes back in Part 8, on lists. Part 18 explains the full rules for when React keeps state and when it throws it away.
TypeScript: a value that might be missing
Often you show something only when a value exists. A user may be logged in, or not:
type User = { name: string }
function Hello({ user }: { user: User | null }) {
return <p>Hello, {user.name}!</p>
}
export default function App() {
return <Hello user={null} />
}
User | null means “a User, or null“. TypeScript stops you here with 'user' is possibly 'null'. It’s right. The playground doesn’t check types, so press Run there. The code runs, and then it crashes. In Chrome, the error is Cannot read properties of null (reading 'name').
Any check that rules out null fixes it. TypeScript reads your check and knows user can’t be null after it. This is called narrowing: the type gets narrower, from “a User or null” to just “a User“.
type User = { name: string }
function Hello({ user }: { user: User | null }) {
if (!user) {
return <p>Hello, guest!</p>
}
return <p>Hello, {user.name}!</p>
}
export default function App() {
return (
<div>
<Hello user={{ name: 'Ana' }} />
<Hello user={null} />
</div>
)
}
After the early return, TypeScript knows user is a User. The same works inside JSX:
{user && user.name}shows the name, or nothing.{user?.name}does the same, and is shorter.?.is called optional chaining. It means “ifuserisnullorundefined, stop here and give backundefined“.{user ? user.name : 'guest'}shows the name, or “guest”.
All three type-check. With user set to null, the first two showed “Hello, !” in our test. Only the ternary filled the gap.
Common mistakes
A number on the left of &&
{count && <List />} shows 0 when count is 0. NaN shows too. Make the left side a real true or false: {count > 0 && <List />}. Or use a ternary.
if inside curly braces
export default function App() {
const ok = true
return (
<div>
{if (ok) { <p>Yes</p> }}
</div>
)
}
Curly braces in JSX take an expression. if is a statement, so TypeScript stops with “Expression expected”.
In the playground, the message is stranger:
This code has a mistake React cannot read: Error transforming App.tsx: Unterminated regular expression (6:7)
A regular expression is a JavaScript pattern for finding text, written between two / signs. Your code has none. But after the if, the playground’s tool can no longer read the rest as JSX. It reads it as plain JavaScript. Then the / in </div>, on line 6, looks like the start of a regular expression. We checked: move </div> two lines down, and the error moves to line 8. So the message names the wrong problem. When an error makes no sense, look for a statement inside { }.
The fix: use a ternary or && inside the braces, or move the if above the return.
A ternary inside a ternary
type Size = 'small' | 'medium' | 'large'
function Label({ size }: { size: Size }) {
return <p>{size === 'small' ? 'S' : size === 'medium' ? 'M' : 'L'}</p>
}
This works, but it is hard to read. With a fourth size, it gets worse. Use an object instead:
type Size = 'small' | 'medium' | 'large'
const labels: Record<Size, string> = { small: 'S', medium: 'M', large: 'L' }
function Label({ size }: { size: Size }) {
return <p>{labels[size]}</p>
}
React’s docs add one more idea. If your conditions get hard to follow, move parts into their own small components.
A hook after an early return
Early returns are useful. But a hook after one breaks the rules of hooks from Part 4. Hooks must run in the same order on every render.
import { useState } from 'react'
function Counter({ show }: { show: boolean }) {
const [label] = useState('Count')
if (!show) {
return null
}
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{label}: {count}</button>
}
export default function App() {
const [show, setShow] = useState(false)
return (
<div>
<button onClick={() => setShow(!show)}>Change</button>
<Counter show={show} />
</div>
)
}
Run it and press “Change”. React stops with Rendered more hooks than during the previous render. The first render called one hook. The next render called two.
Start with useState(true) instead, and press “Change”. Now the error says: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
With only one hook, after the return, it can be worse. We tried it: React showed no error at all. But the counter lost its count. It went from 2 back to 0 after it was hidden and shown again. So no error doesn’t mean no bug.
The fix: call every hook at the top, before any return. Then decide what to show.
Practice
Press Edit on any example above and try these.
- In “Try this first”, use a ternary so that the line says
Mail: no new messageswhencountis 0. - In the first “Remove it” example, move
const [count, setCount] = useState(0)out ofCounterand intoApp. GiveCountertwo props,countandonAdd, and passonAdd={() => setCount(count + 1)}. Click the counter 3 times, then press “Hide” and “Show”. What does it show now? - In the Ana and Ben example with no keys, wrap Ben’s counter in a
<div>:<div><Counter label="Ben" /></div>. Click “Ana” 3 times and press “Switch”. Does Ben get Ana’s count? - Write a
Badgecomponent that takescount. It returnsnullwhencountis 0, and<b>{count}</b>otherwise. Use it in the mail example.
Answers
{count > 0 ? <b>{count} new</b> : 'no new messages'}. At first the page shows “Mail: no new messages”. After one click, it shows “Mail: 1 new”.Count: 3.Counterwas still removed. But the count now lives inApp, andAppwas never removed.Counteronly shows it. Moving state up to a parent like this is the topic of Part 9.- No. Ben shows 0. In that place, React now sees a
<div>where aCounterused to be. A different type of thing in the same place means a new component, with new state. - For example:
function Badge({ count }: { count: number }) {
if (count === 0) {
return null
}
return <b>{count}</b>
}
Then write <p>Mail: <Badge count={count} /></p>. At 0 the page shows “Mail:” and nothing after it. After one click, it shows “Mail: 1”.
Interview questions
Try to answer each one out loud before you open the answer.
What are the ways to show something only sometimes in React?
An if with an early return, before the JSX. An if that fills a variable, used later in the JSX. A ternary, a ? b : c, for two choices. &&, for “this or nothing”. Returning null from a component to show nothing. For many choices, use an object that maps each one to what to show. Or use a switch in a small component.
A strong answer says when to use which. Early returns for very different screens. A ternary for two small choices inside JSX. && only with a real true or false on the left.
What is the 0 bug with the AND operator in JSX?
a && b gives back a when a is falsy. When count is 0, the answer is the number 0, not false. React shows numbers, so a 0 appears on the page. false, null, undefined and empty text show nothing, but 0 and NaN show.
The fixes: {count > 0 && <List />}, {Boolean(count) && <List />}, or a ternary with null. A strong answer adds that TypeScript doesn’t catch it. A number is a valid thing for React to show.
A component returns nothing. Does it still run? Is it still on the page?
It still runs: React calls it, and it decides to return nothing. React adds nothing to the page for it. But React still counts it as part of the tree. So if it calls its hooks before the return null, it keeps its state. In our test, a counter that returned null while hidden still showed its old count when it came back.
A strong answer adds that the hooks must all come before the early return. Otherwise React may throw Rendered more hooks than during the previous render, or Rendered fewer hooks than expected. Or, with no error at all, the state may be lost.
What is the difference between hiding a component and not rendering it?
Not rendering it, with && or a ternary, unmounts it. React removes its tags and throws away its state. When it comes back, it starts fresh. Hiding it, with the hidden attribute or display: none, keeps it mounted. Its tags stay on the page, its state is kept, and it still runs when its parent runs.
A strong answer gives the trade-off. Removing is cheaper while it’s gone. Hiding keeps things like text the user typed. It may also name <Activity mode="hidden">, a React component for this. It is not the same as plain hiding. React’s docs say to think of it this way: “the children are unmounted, but React saves their state for later”. While hidden, its Effects (Part 11) are cleaned up, and its children render at a lower priority. We tried it in React 19.3. A counter inside a hidden Activity kept its count of 3. React kept its button out of sight with display: none !important.
Why does a ternary between two <Counter /> tags keep the same state?
React doesn’t see the ternary. It sees what the component returns. Both branches give a Counter at the same place in the tree. To React, it is the same counter with new props, so it keeps the state.
To reset it, give each branch a different key, like key="a" and key="b". Or put them in two separate places: {isA && <Counter />}{!isA && <Counter />}. A strong answer adds the other side. A different type at the same place, like a <div> where a Counter was, also starts the state over.
Can you call a hook after an early return?
No. Hooks must be called in the same order on every render. React matches each call with its saved value by order. If an early return skips some hooks on one render, the order changes. React may then throw Rendered more hooks than during the previous render, or Rendered fewer hooks than expected. Or it may show no error and lose the state. In our test, one hook after the early return gave no error, and the count went back to 0. Put every hook at the top of the component, and decide what to show after.
A value may be missing. Should you check it with the AND operator, or with optional chaining?
Compare user && user.name with user?.name. Both avoid the crash when user is null, and TypeScript accepts both. When user is null, user && user.name gives null, and user?.name gives undefined. React shows nothing for either one. ?. is shorter, and it stops only for null or undefined. && stops at any falsy value and gives that value back. With a number on the left, that could put a 0 on the page.
Sources
- Conditional Rendering, react.dev:
if,null,? :and&&, the0pitfall (“Don’t put numbers on the left side of &&”), returningnull“isn’t common”, and moving messy conditions into components. - Preserving and Resetting State, react.dev: “the same component at the same position”, keys to reset state, and different places or types resetting it.
- Rules of Hooks, react.dev: hooks only at the top level, not after an early return.
- Activity, react.dev: hiding children while keeping their state.
- Falsy, Logical AND (&&) and Optional chaining (?.), MDN: the falsy values, what
&&gives back, and what?.gives back. - hidden, MDN: the
hiddenattribute, and that CSSdisplaycan override it. - Narrowing, TypeScript handbook: how a check narrows a type.
- The page output, the falsy table, the fixes, the counts and the error messages above come from running React 19.3.0, TypeScript 7.0.2 and Sucrase 3.35.1 for this post.
- This part follows the Conditional Rendering kata in react-katas.