react-hook-patterns
React hooks are functions that let you “hook into” React state and lifecycle features from function components. Here are ten common React hook patterns that might be asked about in an interview:
1. Basic State Hook
Using useState
to add local state to functional components.
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
2. Basic Effect Hook
Using useEffect
to perform side effects in functional components.
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return <button onClick={() => setCount(count + 1)}>Click me</button>;
}
3. Custom Hook
Creating a custom hook to share logic between components.
function useCustomCounter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return { count, increment, decrement };
}
4. Context Hook
Using useContext
to access context values.
const ThemeContext = React.createContext('light');
function Example() {
const theme = useContext(ThemeContext);
return <div>Theme: {theme}</div>;
}
5. Ref Hook
Using useRef
to persist values between renders without triggering a re-render.
function Timer() {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
// ...your code...
}, 1000);
intervalRef.current = id;
return () => clearInterval(intervalRef.current);
}, []);
return <h1>I am a timer</h1>;
}
6. Reducer Hook
Using useReducer
for more complex state logic.
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}
7. Callback Hook
Using useCallback
to memorize callback functions.
function Example({ someProp }) {
const memoizedCallback = useCallback(
() => {
// Perform an action with someProp
},
[someProp],
);
return <ChildComponent onAction={memoizedCallback} />;
}
8. Memo Hook
Using useMemo
to memorize computation results.
function Example({ someProp }) {
const memoizedValue = useMemo(() => computeExpensiveValue(someProp), [someProp]);
return <div>{memoizedValue}</div>;
}
9. Imperative Handle Hook
Using useImperativeHandle
to expose parent components to methods in a child component.
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
}
FancyInput = forwardRef(FancyInput);
10. Layout Effect Hook
Using useLayoutEffect
to read layout from the DOM and synchronously re-render.
function Example() {
useLayoutEffect(() => {
// Read layout from the DOM and cause a synchronous re-render
});
return <div />;
}
Certainly! Here are five additional hook patterns that are often useful in React development:
11. State with Previous Value
Using useState
along with useEffect
to keep track of a state's previous value.
function Example() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
});
const prevCount = prevCountRef.current;
return <h1>Now: {count}, before: {prevCount}</h1>;
}
12. Debounce Hook
Creating a custom useDebounce
hook to debounce any fast-changing value.
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
13. Event Listener Hook
Creating a custom useEventListener
hook to handle event listeners.
function useEventListener(eventName, handler, element = window) {
const savedHandler = useRef();
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
const isSupported = element && element.addEventListener;
if (!isSupported) return;
const eventListener = event => savedHandler.current(event);
element.addEventListener(eventName, eventListener);
return () => {
element.removeEventListener(eventName, eventListener);
};
}, [eventName, element]);
}
14. Update Effect Hook
Creating a custom useUpdateEffect
hook that runs an effect only on updates, not on the initial mount.
function useUpdateEffect(effect, deps) {
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
return effect();
}
}, deps);
}
15. Mounted State Hook
Creating a custom useIsMounted
hook to check if the component is still mounted before setting the state to prevent memory leaks.
function useIsMounted() {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return isMounted;
}
Here are five more React hook patterns:
16. Controlled Input Hook
This custom hook manages the state of an input field, making it easier to create controlled inputs.
function useInput(initialValue) {
const [value, setValue] = useState(initialValue);
function handleChange(e) {
setValue(e.target.value);
}
return {
value,
onChange: handleChange,
};
}
// Usage
function MyForm() {
const email = useInput('');
return (
<input type="email" {...email} />
);
}
17. Form Handling Hook
A custom hook for managing form states and handling submissions.
function useForm(initialState) {
const [values, setValues] = useState(initialState);
const handleChange = (e) => {
const { name, value } = e.target;
setValues(prevValues => ({
...prevValues,
[name]: value
}));
};
const handleSubmit = (callback) => (e) => {
e.preventDefault();
callback();
};
return {
values,
handleChange,
handleSubmit
};
}
// Usage
function MyForm() {
const { values, handleChange, handleSubmit } = useForm({ email: '', password: '' });
const submit = () => {
console.log(values);
};
return (
<form onSubmit={handleSubmit(submit)}>
<input name="email" value={values.email} onChange={handleChange} />
<input name="password" value={values.password} onChange={handleChange} />
<button type="submit">Submit</button>
</form>
);
}
18. Theme Switcher Hook
A hook that provides an easy way to toggle a theme, often used in conjunction with context for theme management.
function useThemeSwitcher() {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
return {
theme,
toggleTheme
};
}
// Usage
function App() {
const { theme, toggleTheme } = useThemeSwitcher();
return (
<div className={`App ${theme}`}>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
19. Async Data Fetch Hook
A hook for fetching data asynchronously, handling loading and error states.
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Usage
function MyComponent() {
const { data, loading, error } = useFetch('https://api.example.com/data');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>{data && data.map(item => <div key={item.id}>{item.title}</div>)}</div>
);
}
20. Timeout Hook
A hook to handle actions after a timeout.
function useTimeout(callback, delay) {
const savedCallback = useRef(callback);
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
if (delay !== null) {
const id = setTimeout(() => savedCallback.current(), delay);
return () => clearTimeout(id);
}
}, [delay]);
}
// Usage
function MyComponent() {
const [count, setCount] = useState(10);
useTimeout(() => setCount(count - 1), count > 0 ? 1000 : null);
return <h1>{count}</h1>;
}
These hooks cover a range of common patterns for handling forms, themes, asynchronous data, and timing in React components.