A Readable useToggle

Naseebullah Ahmadi  Senior Software Engineer, London

A boolean `useState` that hands back `on` / `off` / `toggle` instead of a raw setter, so call sites read as intent. Every function, and the controls object itself, stays referentially stable, safe to pass as props or list as effect dependencies without retriggering anything downstream.

4 min read
#frontend

useState(false) gives you setValue, so every call site ends up spelling out setValue(true), setValue(false), setValue(v => !v). Wrap it once instead, and the intent - on, off, toggle - moves to the call site. The setters and the object holding them stay stable across renders, so they pass cleanly as props or effect deps.

@itsnas panel.tsx
codepanel.tsx
'use client'
 
function AdvancedPanel() {
  // @src/code/use-toggle
  const [isOpen, panel] = useToggle()
 
  // panel.off keeps one identity across renders, so it's an honest
  // effect dep: this runs when isOpen flips, not on every render.
  useEffect(() => {
    if (!isOpen) return
 
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') panel.off()
    }
 
    document.addEventListener('keydown', onKey)
    return () => document.removeEventListener('keydown', onKey)
  }, [isOpen, panel.off])
 
  return (
    <>
      <button onClick={panel.toggle} aria-expanded={isOpen}>
        Advanced settings
      </button>
 
      {isOpen && <fieldset>{/* … */}</fieldset>}
    </>
  )
}
main
Nas (@itsnas)