6 min read

React Coding Interview Snippets

In this post, we will cover some React snippets that are commonly used in coding interviews. These snippets will help you solve React problems more efficiently and demonstrate your knowledge of React patterns and hooks.

Common

Handle button click

function Button() {
  const handleClick = () => {
    console.log('Button clicked!');
  };

  return <button onClick={handleClick}>Click me</button>;
}

useState

Initialize and update state

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

Update state based on previous value

Use the updater function when the new state depends on the previous state.

const [count, setCount] = useState(0);

// ❌ Can cause bugs if called multiple times in the same render
setCount(count + 1);

// ✅ Always safe — uses the latest state value
setCount(prev => prev + 1);

Update object in state

Always spread the previous state when updating objects to avoid losing other properties.

const [user, setUser] = useState({ name: '', age: 0 });

// Update a single field without losing the rest
const updateName = (name) => {
  setUser(prev => ({ ...prev, name }));
};

Update array in state

Use spread or map/filter to produce a new array; avoid mutating the existing array.

const [items, setItems] = useState([1, 2, 3]);

// Add item
setItems((prev) => [...prev, 4]);

// Remove item by index
setItems((prev) => prev.filter((_, i) => i !== 1));

// Update item at index
setItems((prev) => prev.map((item, i) => (i === 1 ? 99 : item)));

useEffect

useEffect with dependency array

Run effect when component mounts or when dependencies change.

useEffect(() => {
  // runs on mount and when userId changes
  fetchUser(userId);
}, [userId]);

useEffect cleanup

Return a function to run cleanup when the component unmounts or before the effect runs again.

useEffect(() => {
  const timer = setInterval(() => {
    console.log('tick');
  }, 1000);

  return () => clearInterval(timer); // cleanup
}, []);

Async logic inside useEffect

Call an async function inside the effect; do not make the effect callback itself async.

useEffect(() => {
  let cancelled = false;

  const load = async () => {
    const data = await fetchData();
    if (!cancelled) setData(data);
  };
  load();

  return () => {
    cancelled = true;
  };
}, []);

useRef

useRef for DOM element

Attach a ref to a DOM element to access it imperatively.

const inputRef = useRef(null);

const focusInput = () => {
  inputRef.current?.focus();
};

return <input ref={inputRef} />;

useRef for mutable value that does not trigger re-render

Store a value that persists across renders without causing updates.

const renderCount = useRef(0);
renderCount.current += 1;

Previous value pattern

Keep track of the previous value of a prop or state using a ref.

const usePrevious = (value) => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
};

const prevCount = usePrevious(count);

Lists & keys

Render list with key

Map over an array and provide a stable key (usually an id) for each item.

const items = [{ id: 1, name: 'a' }, { id: 2, name: 'b' }];

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

Conditional list rendering

Render a list only when it has items, or show a fallback.

{items.length > 0 ? (
  <ul>
    {items.map((item) => <li key={item.id}>{item.name}</li>)}
  </ul>
) : (
  <p>No items</p>
)}

Forms

Controlled input

Value and onChange are driven by state.

const [value, setValue] = useState('');

return (
  <input
    value={value}
    onChange={(e) => setValue(e.target.value)}
  />
);

Controlled checkbox and select

Same pattern: state holds the value, onChange updates it.

const [checked, setChecked] = useState(false);
const [option, setOption] = useState('a');

return (
  <>
    <input
      type="checkbox"
      checked={checked}
      onChange={(e) => setChecked(e.target.checked)}
    />
    <select value={option} onChange={(e) => setOption(e.target.value)}>
      <option value="a">A</option>
      <option value="b">B</option>
    </select>
  </>
);

Conditional rendering

Render with &&

Show content only when a condition is true. Use a boolean to avoid rendering 0.

{isVisible && <Message />}
{items.length > 0 && <List items={items} />}

Render with ternary

Choose one of two branches.

{isLoggedIn ? <Dashboard /> : <Login />}

Early return

Return null or another component to skip rendering the rest.

const Page = ({ user }) => {
  if (!user) return null;
  if (user.isLoading) return <Spinner />;
  return <Content user={user} />;
};

Context

createContext and Provider

Define a context and wrap the tree with a Provider that supplies the value.

const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider value={theme}>
      <Page />
    </ThemeContext.Provider>
  );
}

useContext

Read the value from the nearest Provider of that context.

const theme = useContext(ThemeContext);
return <div className={theme}>...</div>;

Performance

useMemo for expensive computation

Memoize a value so it is only recomputed when dependencies change.

const sortedItems = useMemo(
  () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
  [items]
);

useCallback for stable function reference

Memoize a function so it keeps the same reference when dependencies are unchanged.

const handleClick = useCallback(() => {
  doSomething(id);
}, [id]);

React.memo for component

Prevent re-renders when props are shallowly equal.

const ExpensiveItem = React.memo(function ExpensiveItem({ item }) {
  return <div>{item.name}</div>;
});

Lazy laod a component

React.lazy lets you defer loading a component until it's first rendered, reducing the initial bundle size.

import { lazy, Suspense } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <HeavyComponent />
    </Suspense>
  );
}

Event handlers

Pass argument to handler

Use an arrow function or bind to pass arguments without invoking immediately.

<button onClick={() => handleDelete(item.id)}>Delete</button>
<button onClick={handleDelete.bind(null, item.id)}>Delete</button>

preventDefault and stopPropagation

Control default browser behavior and event bubbling.

const handleSubmit = (e) => {
  e.preventDefault();
  submitForm();
};

const handleClick = (e) => {
  e.stopPropagation();
  onClick();
};

Common patterns

usePrevious hook

Reusable hook to get the previous value of any value.

const usePrevious = (value) => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
};

useLocalStorage hook

Sync state with localStorage so it persists across reloads.

const useLocalStorage = (key, initialValue) => {
  const [value, setValue] = useState(() => {
    try {
      return JSON.parse(localStorage.getItem(key)) ?? initialValue;
    } catch {
      return initialValue;
    }
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
};

Force re-render

Rarely needed; use a state updater to trigger a re-render.

const [, forceUpdate] = useReducer((x) => x + 1, 0);
// Call forceUpdate() to re-render