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