我写了一个react-hooks,不再需要处理超时。就像 React.useState() 一样工作:
新答案
const [showLoading, setShowLoading] = useTimeoutState(false)
// sets loading to true for 1000ms, then back to false
setShowLoading(true, { timeout: 1000})
export const useTimeoutState = <T>(
  defaultState: T
): [T, (action: SetStateAction<T>, opts?: { timeout: number }) => void] => {
  const [state, _setState] = useState<T>(defaultState);
  const [currentTimeoutId, setCurrentTimeoutId] = useState<
    NodeJS.Timeout | undefined
  >();
  const setState = useCallback(
    (action: SetStateAction<T>, opts?: { timeout: number }) => {
      if (currentTimeoutId != null) {
        clearTimeout(currentTimeoutId);
      }
      _setState(action);
      const id = setTimeout(() => _setState(defaultState), opts?.timeout);
      setCurrentTimeoutId(id);
    },
    [currentTimeoutId, defaultState]
  );
  return [state, setState];
};
旧答案
const [showLoading, setShowLoading] = useTimeoutState(false, {timeout: 5000})
// will set show loading after 5000ms
setShowLoading(true)
// overriding and timeouts after 1000ms
setShowLoading(true, { timeout: 1000})
设置多个状态将刷新超时,并在与上次setState设置相同的毫秒后超时。
Vanilla js(未测试,typescript版本是):
import React from "react"
// sets itself automatically to default state after timeout MS. good for setting timeouted states for risky requests etc.
export const useTimeoutState = (defaultState, opts) => {
  const [state, _setState] = React.useState(defaultState)
  const [currentTimeoutId, setCurrentTimeoutId] = React.useState()
  const setState = React.useCallback(
    (newState: React.SetStateAction, setStateOpts) => {
      clearTimeout(currentTimeoutId) // removes old timeouts
      newState !== state && _setState(newState)
      if (newState === defaultState) return // if already default state, no need to set timeout to set state to default
      const id = setTimeout(
        () => _setState(defaultState),
        setStateOpts?.timeout || opts?.timeout
      ) 
      setCurrentTimeoutId(id)
    },
    [currentTimeoutId, state, opts, defaultState]
  )
  return [state, setState]
}
typescript:
import React from "react"
interface IUseTimeoutStateOptions {
  timeout?: number
}
// sets itself automatically to default state after timeout MS. good for setting timeouted states for risky requests etc.
export const useTimeoutState = <T>(defaultState: T, opts?: IUseTimeoutStateOptions) => {
  const [state, _setState] = React.useState<T>(defaultState)
  const [currentTimeoutId, setCurrentTimeoutId] = React.useState<number | undefined>()
  // todo: change any to React.setStateAction with T
  const setState = React.useCallback(
    (newState: React.SetStateAction<any>, setStateOpts?: { timeout?: number }) => {
      clearTimeout(currentTimeoutId) // removes old timeouts
      newState !== state && _setState(newState)
      if (newState === defaultState) return // if already default state, no need to set timeout to set state to default
      const id = setTimeout(
        () => _setState(defaultState),
        setStateOpts?.timeout || opts?.timeout
      ) as number
      setCurrentTimeoutId(id)
    },
    [currentTimeoutId, state, opts, defaultState]
  )
  return [state, setState] as [
    T,
    (newState: React.SetStateAction<T>, setStateOpts?: { timeout?: number }) => void
  ]
}```