Professional React · Lesson 16 of 21
Writing your own hooks
Pull repeated logic into a use… function and reuse it anywhere.
If the same useState + useEffect keep repeating across components, extract them into a custom hook: a plain function whose name starts with use and which calls hooks. Each component using it gets its own copy of the state, so hooks share logic, not data.
function useToggle(initial = false) {
const [on, setOn] = useState(initial)
const toggle = useCallback(() => setOn((v) => !v), [])
return [on, toggle]
}
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 App() {
const [menu, toggleMenu] = useToggle()
const [dark, toggleDark] = useToggle(true)
const width = useWindowWidth()
return (
<div>
<p>Preview width: {width}px ({width < 500 ? "phone" : "wide"})</p>
<button onClick={toggleMenu}>Menu: {menu ? "open" : "closed"}</button>
<button onClick={toggleDark}>Theme: {dark ? "dark" : "light"}</button>
</div>
)
}- useToggle() (one piece of logic)
- App → menu: its own state
- App → dark: its own state
The same hook called twice; each call has separate state.
Complete the code
Complete the hook that returns an input's value and its handler.
function Input(initial) { const [value, setValue] = (initial) return { value, onChange: (e) => setValue(e.target.value) } } function App() { const name = useInput("") return <input {...name} /> }
Exercise
Write useCounter(start) returning { count, inc, reset }, and use it twice independently in App: Likes from 0 and Stars from 10. The checker presses Likes twice and Stars once.
The page should show: Likes 2 Stars 11
function useCounter(start) {
return { count: start, inc: () => {}, reset: () => {} }
}
function App() {
const likes = useCounter(0)
const stars = useCounter(10)
return (
<div>
<button className="likes" onClick={likes.inc}>Likes {likes.count}</button>
<button className="stars" onClick={stars.inc}>Stars {stars.count}</button>
</div>
)
}Learn more from
Played 0 of 2 games
Sign in to save your progress and earn XP.