Skip to content

A Flag That Lowers Itself

Naseebullah AhmadiSenior Software Engineer, London

A "Copied" tick, a "Saved" badge, a shake on a wrong password: state that should be true for a moment and then go back on its own. `useMomentaryFlag` is that boolean, with the timer handled.

4 min read
#frontend

The obvious version is setCopied(true) and a setTimeout(() => setCopied(false), 1500) next to it, and it has two bugs. Click twice and the first timer clears the flag early, halfway through the second "Copied". Navigate away before it fires and the timer sets state on a component that's gone. This hook keeps one timer, restarts it on every raise(), and clears it on unmount.

@itsnas copy-button.tsx
codecopy-button.tsx
'use client'
 
function CopyButton({ getText }: { getText: () => string }) {
  // @src/code/use-momentary-flag
  const [copied, markCopied] = useMomentaryFlag(1500)
 
  async function handleCopy() {
    await navigator.clipboard.writeText(getText())
    markCopied()
  }
 
  return (
    <>
      <button onClick={handleCopy} type="button">
        {copied ? 'Copied' : 'Copy'}
      </button>
 
      {/* Mounted up front so screen readers announce the change. */}
      <span className="sr-only" role="status">
        {copied ? 'Copied' : ''}
      </span>
    </>
  )
}
main
Nas (@itsnas)

useToggle is the readable useToggle snip; its on and off keep one identity across renders, which is what keeps raise stable enough to pass as a prop. A plain useState with setFlag(true) and setFlag(false) works just as well.