React Intermediate: Forms, Hooks and State
Hooks in Depth
In this lesson you will
- Use useRef for values that should not cause a re-render
- Write correct effect dependency lists and clean-up functions
- Extract reusable logic into a custom hook
Introduction
Hooks let function components use state and other React features. You know useState and useEffect. This lesson covers the others you will use constantly, and how to write your own.
useRef
A ref holds a value that persists between renders, but changing it does not cause a re-render. Two main uses:
React (JSX)
import { useRef, useEffect } from "react";
function SearchBox() {
const inputRef = useRef(null); // a reference to a DOM element
useEffect(() => {
inputRef.current.focus(); // focus the input when it first appears
}, []);
return <input ref={inputRef} placeholder="Search" />;
}- Reaching a DOM element to focus it, scroll it or measure it.
- Storing a mutable value, such as a timer ID, that does not affect what is shown.
Never read or write ref.current while rendering. Use it in event handlers and effects.
Quick quiz
What happens when you change ref.current?
Effect dependencies
The dependency array tells React when to re-run an effect:
React (JSX)
useEffect(() => {
document.title = `${count} new messages`;
}, [count]);[]means run once after the first render.[count]means run after the first render, and again whenevercountchanges.- No array means run after every render, which is rarely what you want.
The rule: list every value from the component that the effect uses. Leaving one out causes stale values and subtle bugs. The ESLint plugin react-hooks/exhaustive-deps warns you, so keep it on.
Clean-up
An effect can return a function that runs before the next run and when the component is removed. Use it to undo what the effect started:
React (JSX)
useEffect(() => {
function onResize() { setWidth(window.innerWidth); }
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
}, []);Without the clean-up, listeners pile up and leak memory.
You may not need an effect
Effects are for synchronising with things outside React: the network, timers, the browser. If you can compute something from props or state, do it during rendering. If something happens because of a click, put it in the event handler.
useMemo and useCallback
These cache a value or a function between renders:
React (JSX)
const visible = useMemo(() => items.filter((i) => i.done === showDone), [items, showDone]);
const handleSave = useCallback(() => save(form), [form]);Use them when a calculation is genuinely slow, or when you pass a function to a memoised child. Do not scatter them everywhere, because they add complexity and measuring comes first.
Custom hooks
A custom hook is a function whose name starts with use and that calls other hooks. It shares logic (not state) between components.
React (JSX)
import { useState, useEffect } from "react";
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const onResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
}, []);
return width;
}
function Banner() {
const width = useWindowWidth();
return <p>{width < 600 ? "Mobile layout" : "Desktop layout"}</p>;
}Each component that calls useWindowWidth gets its own state.
Rules of hooks
- Call hooks only at the top level of a component or custom hook, never in loops, conditions or nested functions.
- Call hooks only from React functions.
React relies on the order of hook calls, so the order must be the same on every render.
Try it yourself
Write a useLocalStorage(key, initial) custom hook that works like useState but saves the value in the browser's localStorage. Use it for a theme setting.
Summary
useRefholds values or DOM elements without causing re-renders.- Effects need correct dependency lists and clean-up, and are only for syncing with the outside world.
- Custom hooks share logic between components, and hooks must follow the rules of hooks.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading