Skip to content
Chapter 16Lesson 5

Quiz - Browser capability APIs

Quiz progress

0 / 0

Your Copy button works on localhost and in production, but a teammate testing the staging build over a plain http:// LAN address reports it crashes the whole component instead of just failing quietly. The handler is the canonical shape:

const copy = async () => {
try {
await navigator.clipboard.writeText(value);
setCopied(true);
} catch (error) {
if (error.name === 'SecurityError') showInsecureBanner();
}
};

Why does the insecure-context case never reach that catch?

On plain http://, navigator.clipboard is undefined, so reading .writeText off it throws a synchronous TypeError before any Promise exists to reject — there’s nothing for the catch to catch. Insecure context is a deployment bug handled by feature-detection, not a rejection branch.

The call does reject with a SecurityError, but error.name is actually 'NotAllowedError' in an insecure context, so the if condition never matches and the banner never shows.

try/catch can’t catch errors from an awaited call unless you also wrap it in .catch(), so the rejection escapes to the nearest error boundary and unmounts the component.

You’re choosing the signature primitive for two features. (A) A Stripe webhook you receive: Stripe and your server share a secret agreed out of band, and your handler must confirm an incoming payload was signed with it. (B) A public “verifiable receipt” anyone — including parties who must never hold your secret — should be able to verify came from you. For which feature is HMAC the right reach?

(A) only. HMAC is symmetric — the same secret signs and verifies — which fits the webhook, where both ends already share that secret. (B) needs different signer and verifier actors with no shared secret, which is asymmetric crypto, not HMAC.

Both. HMAC with SHA-256 is the 2026 default for any signature, and the public-verification case just means publishing the same HMAC secret so verifiers can check it.

(B) only. HMAC’s keyed hash is what lets anyone verify, while the webhook in (A) should use a plain digest of the body since both ends already trust each other.

A reviewer flags your avatar preview for leaking a Blob on every re-pick, so you “add the cleanup” by revoking on the line right after you create the handle:

const url = URL.createObjectURL(file);
setPreviewUrl(url);
URL.revokeObjectURL(url);

What happens to the preview, and where does the revoke actually belong?

The preview renders blank (broken-image icon): <img> reads the bytes asynchronously, a beat after src is set, and you’ve already deleted the map entry by then. The revoke belongs in the effect’s cleanup return — keyed to the file — so it runs on the next pick or on unmount, after the element has read the bytes.

It works correctly and leak-free: the synchronous revoke runs after setPreviewUrl, so React has already painted the <img> with the bytes by the time the handle is released.

The preview still leaks: revoking the same URL you just created is a no-op, so you have to call revokeObjectURL on the previous url in a ref to actually release anything.

A Coachmark reads its dismissed flag straight from localStorage in the component body and crashes with ReferenceError: localStorage is not defined. A teammate suggests adding 'use client' at the top of the file to fix it. Will that work?

No. A Client Component still pre-renders on the server to produce the initial HTML, and there’s no window/localStorage there — so a read in the component body throws during that pre-render regardless of 'use client'. The fix is to defer the read into an effect (or useSyncExternalStore), so it runs only after the component mounts in the browser.

Yes. 'use client' marks the file as browser-only, so its code never runs on the server and the localStorage read is safe.

No, but the real fix is suppressHydrationWarning on the element — it tells React to skip the server render for that subtree, which is what actually causes the ReferenceError.

Run each piece of state through the five-home decision tree (useState → URL → server → cookie → localStorage). Which of these correctly belong in localStorage? Select all that apply.

A dismissed onboarding banner — cheap to lose, not worth a server round-trip, meaningful only on this one device.

Recently-viewed product ids on this device, where it’s fine if a different device shows a different list.

The signed-in user’s auth session token, so it survives reloads without a server round-trip.

The active table filter you want a coworker to reproduce by pasting the link.

Quiz complete

Score by topic