Context & Reducers

Preview — 3 of 10 questions

What is the performance problem here?

javascript
const useStore = create(() => ({
  user: { name: "Alice", age: 25 },
  theme: "light",
  todos: [],
}));

// Component A:
function Header() {
  const store = useStore(); // ❌ no selector
  return <h1>{store.user.name}</h1>;
}

// Component B:
function ThemeToggle() {
  const theme = useStore(s => s.theme); // ✅ selector
  return <button>Mode: {theme}</button>;
}
ABoth components have the same re-render behavior
BHeader is correct because it needs the full user object
CZustand doesn't support selectors
DHeader re-renders on ANY store change (todos update, theme change) — the entire store is subscribed; ThemeToggle only re-renders when theme changes — selectors prevent unnecessary re-renders

What is an optimistic update?

javascript
function LikeButton({ postId, initialLikes }) {
  const [likes, setLikes] = useState(initialLikes);
  const [liked, setLiked] = useState(false);

  const handleLike = async () => {
    // Optimistic update — immediately update UI
    setLikes(l => l + 1);
    setLiked(true);

    try {
      await api.likePost(postId);
    } catch (error) {
      // Rollback on failure
      setLikes(l => l - 1);
      setLiked(false);
    }
  };

  return <button onClick={handleLike}>{liked ? "" : ""} {likes}</button>;
}
AOptimistic updates wait for server confirmation before updating the UI
BOptimistic updates apply state changes immediately to the UI assuming success, then roll back if the server request fails — creates a responsive feel even over slow networks
COptimistic updates are only possible with Zustand or Redux
DOptimistic updates should never be rolled back — consistency doesn't matter

What is the main advantage of this reducer pattern?

javascript
const reducer = (state, action) => {
  switch (action.type) {
    case "SUBMIT_START":
      return { ...state, loading: true, error: null };
    case "SUBMIT_SUCCESS":
      return { loading: false, error: null, data: action.payload };
    case "SUBMIT_ERROR":
      return { ...state, loading: false, error: action.payload };
    default:
      return state;
  }
};
AAll transitions are in one place — impossible to accidentally have loading: true AND error: "failed" at the same time; each action defines the complete valid next state
BThe reducer prevents invalid state combinations
CReducers are slower than multiple useState calls
DYou can have the same invalid state combinations as with multiple useState calls

Sign up free to play

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