Custom Hooks — Series 3

Preview — 3 of 10 questions

What is the key behavioral difference between calling bumpRef and calling bumpState?

javascript
const countRef = useRef(0);
const [countState, setCountState] = useState(0);

function bumpRef() {
  countRef.current += 1;
  console.log(countRef.current); // updated
}

function bumpState() {
  setCountState(c => c + 1);
}
AUpdating .current on a ref never triggers a re-render; calling the state setter does trigger one — countRef.current changes silently in the background, while countState changing causes the component to render again with the new value on screen
BuseRef can only hold references to DOM elements — any other kind of value, like a plain number, requires useState instead
CRef values are shared globally across every instance of the component, while state values are private to each instance
DuseRef only works inside class components, not function components

Why use useId() here instead of just hardcoding id="password" on both elements?

javascript
function PasswordField() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Password</label>
      <input id={id} type="password" />
    </>
  );
}
AuseId() is required syntax whenever a component renders more than one JSX element
BuseId() and hardcoding a fixed string produce identical behavior in every situation — this is purely a style preference
CuseId() generates a stable, unique-per-instance ID string — so if PasswordField is rendered more than once on the same page, each instance gets its own distinct id/htmlFor pair instead of colliding on a duplicate hardcoded "password" id (which breaks the label/input association and violates the rule that DOM ids must be unique per document); it's also designed to avoid server/client ID mismatches during SSR hydration
DuseId() regenerates a brand-new id on every re-render, which is what keeps the label and input correctly linked

What problem does useContext solve here, given Button is nested several levels below App?

javascript
const ThemeContext = createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Layout />
    </ThemeContext.Provider>
  );
}

function Button() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Click</button>;
}
AIt replaces useState entirely for any data considered "global"
BIt eliminates prop drilling by making a value available to any descendant component — Button reads theme directly, without Layout (or anything else in between) needing to explicitly receive and forward it as a prop
CIt automatically speeds up rendering by skipping re-renders for every component that consumes it
DIt stores the value in the browser's localStorage automatically

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.