Checkpoint: React Fundamentals
This checkpoint is a review milestone that consolidates the React Fundamentals track — JSX, props, fragments, rendering, styling, Strict Mode, effect timing, and immutable state — through a hands-on build challenge and a short quiz. It confirms you can combine these ideas before moving on to deeper hooks.
Learn Checkpoint: React Fundamentals in our free React course — an interactive lesson with runnable examples, a practice exercise and a quick recall.
Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
JSX In Depth — JSX is sugar for createElement objects; {' '} embeds expressions; attributes are camelCase; return one root.
Props & One-Way Data Flow — read-only inputs flow down; events flow up via callbacks; children wraps content.
Fragments — group siblings with and add zero DOM nodes.
How Rendering Works — render builds a virtual DOM; reconciliation diffs it; only changes are committed; a re-render is not always a DOM update.
Styling — className , camelCase inline style objects, scoped CSS Modules, conditional classes.
Strict Mode — dev-only double-invoke surfaces impurity and missing cleanup.
useLayoutEffect vs useEffect — before paint vs after paint; measure-and-adjust layout in the pre-paint hook.
Immutable State Updates — never mutate; copy with spread; add/remove/update arrays with spread/filter/map.
🛠️ Build Challenge: A Tiny To-Do Model
Implement four pure, immutable helpers for a to-do list, then run the three steps. None of your helpers may mutate the list they receive — each returns a brand-new array. This mirrors exactly how you would update React state.
1. addTodo(list, text) — append {' '} using spread.
2. toggleTodo(list, id) — map the list, flipping done on the match.
3. removeTodo(list, id) — filter out that id.
4. summary(list) — return "DONE/TOTAL done" .
Order the lifecycle of one state update, the thread running through this whole track:
📋 Quick Reference
React.createElement calls returning plain element objects.
Down via props; events flow back up via callback props.
React compares by reference; a new value is how it detects the change and re-renders.
🔎 Predict-the-Output Self-Test
Guess each line before running it. This checks that reference equality and shallow copies really clicked.
1. Why must a component return one root element?
The return is a single expression compiling to one element. Group siblings in a fragment .
2. A child needs to tell its parent a value changed. How?
The parent passes a callback prop; the child calls it. Data flows down, events flow up.
No. React diffs the new tree and commits only the changes; an unchanged tree leaves the DOM alone.
4. You write items.push(x) then setState and nothing updates. Why?
Same reference — React bails out. Pass a new array: .
5. When does useLayoutEffect run relative to paint?
Synchronously before paint (useEffect runs after). Use it only for measure-and-adjust layout.
6. Why does an effect sometimes run twice in development?
Strict Mode double-invokes (run, cleanup, run) to surface missing cleanup. It is dev-only.
Practice quiz
What does JSX compile down to?
- Raw HTML strings inserted into the DOM
- Template literals evaluated at runtime
- React.createElement calls that return plain element objects
- A separate .html file loaded by the bundler
Answer: React.createElement calls that return plain element objects. JSX is syntactic sugar for React.createElement(...) calls, which return plain JavaScript objects describing the UI.
Why must a component's return contain a single root element?
- Because the return is one expression that compiles to one element; group siblings in a fragment
- Because React only renders the first element it finds
- Because multiple roots make the DOM slower
- Because className can only be applied to one node
Answer: Because the return is one expression that compiles to one element; group siblings in a fragment. A return is a single expression compiling to one element. Wrap multiple siblings in a fragment <>...</> to satisfy this.
How do props behave in React?
- They are mutable and can be reassigned by the child
- They flow up from child to parent automatically
- They are global and shared across all components
- They are read-only inputs that flow down from parent to child
Answer: They are read-only inputs that flow down from parent to child. Props are read-only. Data flows down via props; events flow back up via callback props.
A child needs to tell its parent that a value changed. What is the idiomatic way?
- Mutate the prop directly inside the child
- The parent passes a callback prop and the child calls it
- Use a global variable both can read
- The child re-renders the parent manually
Answer: The parent passes a callback prop and the child calls it. Data flows down, events flow up: the parent passes a callback prop, and the child invokes it to report the change.
What is a fragment used for?
- To group sibling elements while adding zero extra DOM nodes
- To add an extra wrapper div to the DOM
- To memoize a component
- To pass props to many children at once
Answer: To group sibling elements while adding zero extra DOM nodes. A fragment <>...</> groups siblings into one root without rendering any additional DOM node.
Does every re-render result in a DOM update?
- Yes, every render rewrites the entire DOM
- Only when state is an object
- No; React diffs the new tree and commits only the changes
- Only in production builds
Answer: No; React diffs the new tree and commits only the changes. React builds a virtual DOM, reconciles it against the previous tree, and commits only the differences. An unchanged tree leaves the DOM alone.
You call items.push(x) then setState, but nothing updates. Why?
- push is asynchronous
- The array reference is unchanged, so React bails out of the update
- setState only works with numbers
- You must call render() manually after push
Answer: The array reference is unchanged, so React bails out of the update. Mutating in place keeps the same reference. React compares by reference, so it skips the update. Pass a new array like [...items, x].
When does useLayoutEffect run relative to the browser paint?
- After paint, like useEffect
- Only on unmount
- It never runs in development
- Synchronously before paint
Answer: Synchronously before paint. useLayoutEffect runs synchronously before paint (useEffect runs after). Use it only for measure-and-adjust layout work.
Why does an effect sometimes run twice in development?
- Because of a bug in React
- Because Strict Mode double-invokes effects to surface missing cleanup
- Because the dependency array is empty
- Because useEffect always runs twice in every environment
Answer: Because Strict Mode double-invokes effects to surface missing cleanup. Strict Mode intentionally mounts, unmounts, and remounts in development (run, cleanup, run) to reveal effects that are missing cleanup. It is dev-only.
How do you apply an inline style object in JSX?
- style='color: red' as a plain string
- css={{ color: 'red' }}
- style={{ color: 'red' }} with a camelCased object
- inline-style='color: red'
Answer: style={{ color: 'red' }} with a camelCased object. Inline styles take an object with camelCased properties, e.g. style={{ backgroundColor: 'blue' }}. Use className for CSS classes.