Skip to content

Coding practice

React Coding Questions

20 hands-on challenges with prompts and solution sketches for React interview rounds.

Challenge set

20 coding questions

1. Controlled Input

jsx

Build a controlled text input.

function NameField() {
  const [value, setValue] = useState("");
  return (
    <input value={value} onChange={(e) => setValue(e.target.value)} />
  );
}

2. Toggle State

jsx

Toggle a boolean with a button.

function Toggle() {
  const [on, setOn] = useState(false);
  return <button onClick={() => setOn((v) => !v)}>{on ? "On" : "Off"}</button>;
}

3. List Rendering

jsx

Render a list with stable keys.

function ItemList({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.label}</li>
      ))}
    </ul>
  );
}

4. Fetch on Mount

jsx

Fetch data once on mount with cleanup.

function Users() {
  const [users, setUsers] = useState([]);
  useEffect(() => {
    let active = true;
    fetch("/api/users")
      .then((r) => r.json())
      .then((data) => {
        if (active) setUsers(data);
      });
    return () => {
      active = false;
    };
  }, []);
  return <pre>{JSON.stringify(users, null, 2)}</pre>;
}

5. Custom Hook

jsx

Create a useLocalStorage hook.

function useLocalStorage(key, initial) {
  const [value, setValue] = useState(() => {
    const raw = localStorage.getItem(key);
    return raw ? JSON.parse(raw) : initial;
  });
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);
  return [value, setValue];
}

6. Memoized Expensive Calc

jsx

Memoize a derived value with useMemo.

function Total({ items }) {
  const total = useMemo(
    () => items.reduce((sum, item) => sum + item.price, 0),
    [items]
  );
  return <p>Total: {total}</p>;
}

7. Callback Stability

jsx

Stabilize a callback with useCallback.

function Parent({ onSave }) {
  const handleSave = useCallback(() => onSave(), [onSave]);
  return <Child onSave={handleSave} />;
}

8. Error Boundary Usage

jsx

Wrap a subtree with an error boundary component.

function App() {
  return (
    <ErrorBoundary fallback={<p>Something went wrong.</p>}>
      <Dashboard />
    </ErrorBoundary>
  );
}

9. Conditional Render

jsx

Render loading, error, and success states.

function Profile({ status, user, error }) {
  if (status === "loading") return <p>Loading...</p>;
  if (status === "error") return <p>{error}</p>;
  return <h1>{user.name}</h1>;
}

10. Form Submit Handler

jsx

Prevent default and read FormData.

function LoginForm({ onSubmit }) {
  function handleSubmit(e) {
    e.preventDefault();
    const data = new FormData(e.currentTarget);
    onSubmit(Object.fromEntries(data));
  }
  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" />
      <button type="submit">Login</button>
    </form>
  );
}

11. Context Provider

jsx

Create a theme context provider.

const ThemeContext = createContext("light");
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

12. Reducer Counter

jsx

Manage counter state with useReducer.

function reducer(state, action) {
  switch (action.type) {
    case "inc":
      return { count: state.count + 1 };
    case "dec":
      return { count: state.count - 1 };
    default:
      return state;
  }
}
function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: "inc" })}>+</button>
    </>
  );
}

13. Portal Modal

jsx

Render a modal into document.body with createPortal.

function Modal({ children }) {
  return createPortal(
    <div className="modal">{children}</div>,
    document.body
  );
}

14. Debounced Search

jsx

Debounce search input with useEffect.

function Search({ onSearch }) {
  const [query, setQuery] = useState("");
  useEffect(() => {
    const id = setTimeout(() => onSearch(query), 300);
    return () => clearTimeout(id);
  }, [query, onSearch]);
  return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}

15. Optimistic UI

jsx

Optimistically update a liked state.

async function likePost(id, setLiked) {
  setLiked(true);
  try {
    await fetch(`/api/posts/${id}/like`, { method: "POST" });
  } catch {
    setLiked(false);
  }
}

16. Forwarded Ref Input

jsx

Forward a ref to an input.

const TextInput = forwardRef(function TextInput(props, ref) {
  return <input ref={ref} {...props} />;
});

17. Derived Filtered List

jsx

Filter items without extra state.

function FilteredList({ items, query }) {
  const filtered = items.filter((item) =>
    item.name.toLowerCase().includes(query.toLowerCase())
  );
  return filtered.map((item) => <div key={item.id}>{item.name}</div>);
}

18. Cleanup Subscription

jsx

Unsubscribe on unmount.

useEffect(() => {
  const unsubscribe = store.subscribe(setState);
  return () => unsubscribe();
}, []);

19. Lazy Route Component

jsx

Lazy-load a page component.

const Dashboard = lazy(() => import("./Dashboard"));
function App() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <Dashboard />
    </Suspense>
  );
}

20. Key Remount Trick

jsx

Force remount by changing key.

function Editor({ draftId }) {
  return <RichText key={draftId} />;
}