All quizzesEasy
Local State & Lifting — Series 2
Preview — 3 of 10 questions
Clicking the button doesnt cause the new item to visually appear, even though `items` genuinely now contains `Bread'`. Why?
javascript
function ShoppingList() {
const [items, setItems] = useState(['Milk', 'Eggs']);
function addItem(newItem) {
items.push(newItem); // mutating the array directly
setItems(items);
}
return (
<>
<ul>{items.map((item, i) => <li key={i}>{item}</li>)}</ul>
<button onClick={() => addItem('Bread')}>Add Bread</button>
</>
);
}A.push() is not a valid method to call on state — it throws a runtime error, which is why nothing appears
BsetItems(items) is being called with the same array reference that was just mutated in place — React's useState setter compares the new value to the current one via Object.is, and since it's literally the same reference (Object.is(items, items) is always true), React sees "no change" and skips re-rendering entirely, even though the array's contents did change
CThe component actually does re-render correctly — the real issue is that the key={i} (index) prevents new items from displaying
DuseState arrays have a fixed maximum length of 2 by default, silently rejecting any further pushes
Typing into the textarea doesnt actually update whats displayed, even though profile.bio is genuinely being changed. What's the fix?
javascript
function ProfileEditor() {
const [profile, setProfile] = useState({ name: 'Alex', bio: '' });
function updateBio(newBio) {
profile.bio = newBio; // mutating the object directly
setProfile(profile);
}
return <textarea value={profile.bio} onChange={e => updateBio(e.target.value)} />;
}AReplace setProfile(profile) with a new object: setProfile({ ...profile, bio: newBio }) — spreading the previous fields and overriding only bio creates a fresh object reference, which React correctly recognizes as "changed"
BAdd a key prop to the <textarea> to force it to re-render on every keystroke
CReplace useState with useRef, since refs update immediately without needing a new reference
DWrap the component in React.memo so it re-renders correctly on internal state changes
This works correctly for a single button clicked one at a time. Why might setIsOpen(prev => !prev) (the functional updater form) be considered more robust than setIsOpen(!isOpen), even though both behave identically in this exact example?
javascript
function Accordion() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
{isOpen && <p>Accordion content</p>}
</>
);
}AsetIsOpen(!isOpen) doesn't actually compile — TypeScript requires the functional form for boolean state specifically
BThere's no meaningful difference in either version, ever, under any circumstances — this is purely a stylistic preference with zero practical impact
CsetIsOpen(!isOpen) reads isOpen from the render-time closure — if this update were ever queued alongside another update to the same state within the same event/batch (e.g., called twice in a row, or from two different handlers batched together), each call would compute !isOpen from that same stale closure value, potentially producing an incorrect final result; setIsOpen(prev => !prev) always operates on the most recently queued value, making it safe regardless of how many times it's called within one batch
DsetIsOpen(!isOpen) triggers two renders instead of one, while the functional form only triggers a single render
Sign up free to play
Answer all 10 questions (7 more), see explanations for every answer, and track your score.