useTemporaryState (React)

Temporarily set a piece of state, and have it cleared after a timeout. Useful for things like a copy or download button, to temporarily show that the action has been triggered.

typescriptjavascript
import type { SetStateAction, Dispatch } from 'react'
import { useState, useCallback, useRef, useEffect } from 'react'
 
export const useTemporaryState = <State>(
  initial: State | (() => State),
  timeout = 2000
): [State, Dispatch<SetStateAction<State>>] => {
  const [state, _setState] = useState<State>(initial)
  const timeoutRef = useRef<ReturnType<typeof setTimeout>>()
  const initialValueRef = useRef(initial)
 
  useEffect(() => {
    initialValueRef.current = initial
  }, [initial])
 
  const setState: typeof _setState = useCallback(
    async valueOrUpdater => {
      _setState(valueOrUpdater)
      if (timeoutRef.current) clearTimeout(timeoutRef.current)
      timeoutRef.current = setTimeout(
        () => _setState(initialValueRef.current),
        timeout
      )
    },
    [timeout]
  )
 
  return [state, setState]
}
import { useState, useCallback, useRef, useEffect } from 'react'
 
export const useTemporaryState = (initial, timeout = 2000) => {
  const [state, _setState] = useState(initial)
  const timeoutRef = useRef()
  const initialValueRef = useRef(initial)
 
  useEffect(() => {
    initialValueRef.current = initial
  }, [initial])
 
  const setState = useCallback(
    async valueOrUpdater => {
      _setState(valueOrUpdater)
      if (timeoutRef.current) clearTimeout(timeoutRef.current)
      timeoutRef.current = setTimeout(
        () => _setState(initialValueRef.current),
        timeout
      )
    },
    [timeout]
  )
 
  return [state, setState]
}

Info

  • We use useCallback, so that if you follow hook rules and use the copy function inside a useEffect or another useCallback, you won't have code (re-)running unnecessarily.

  • We need the combination of useRef and useEffect to store the initial value as it ensures the setState callback isn't re-created if it changes.

Demo

Example

Created 19/06/23Updated 13/09/23
Found a mistake, or want to suggest an improvement? Source on GitHub here
and see edit history here