自定义钩子:不可变的 useState 来存储函数并避免无限循环 [英] Custom hook: immutable useState to store functions and avoid infinite loop

查看:116
本文介绍了自定义钩子:不可变的 useState 来存储函数并避免无限循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以使用 useState 钩子来存储一个不可变对象,该对象包含更新自定义钩子中另一个状态的函数吗?

我有一个自定义 Hook,用于简化应用程序中超时的使用:

I have a custom Hook that I use to simplify the usage of Timeouts inside my app:

export const useTimer = () => {
  const [timer, setTimerObject] = useState<NodeJS.Timeout | null>(null)
  
  //Function to set a new timer. If a timer is already present it is
  //canceled and substituted (useEffect)
  function setTimer(callback:(...args:any[])=>void,ms:number){
    setTimerObject(setTimeout(callback,ms))
  }

  //Function to clear the timer (if there's one)
  function clearTimer(){
    setTimerObject(null);
  }

  //shouldComponentUpdate: delete previous timer if a new timer is issued
  //work also as componentWillUnmount
  useEffect(() => {
    return () => {
      if (timer) clearTimeout(timer)
    }
  }, [timer])

  return ({
    setTimer,
    clearTimer
  })
}

由于我在钩子的末尾返回了一个对象,所以每次我在 useEffect 钩子中设置一个新的计时器时,它都会启动一个无限循环.

Since I return an object at the end of the hook, every time I set a new timer in a useEffect hook, it starts an infinite loop.

const timer = useTimer();

 useEffect(() => {
    if (showError===null) { //Just a random condition to
      setShowError("My error");
      timer.setTimer(() => setShowError(null), 2000) //INFINITE LOOP
    }
  }, [timer, showError])

为了避免在每个设置状态重新渲染,我修改了我的钩子以使用包含更新计时器功能的固定状态.我没有使用两个 useCallback() 钩子,因为如果我的自定义钩子返回一个包含两个回调的对象,回调地址保持不变,但是指向回调的对象会在每次 setState 调用时发生变化,从而产生无限循环.但是,通过使用不可变状态钩子,对象引用不会改变,从而允许我的自定义钩子避免无限循环.这种方法是否会导致可能导致我的代码出现意外行为的问题,或者是否存在满足此特定用例的反应钩子?

To avoid re-renders at every set state I modified my hook to use a fixed state that contains the functions to update the timer. I didn't use two useCallback() hooks because, if my custom hook returns an object containing the two callbacks, the callback address remains the same, but the object pointing at the callbacks will change at every setState call, generating an infinite loop. However, by using an immutable state Hook, the object reference doesn't change, allowing my custom hook to avoid infinite loops. Does this approach causes problems that might lead to unexpected behavior of my code, or there is a react hook that satisfies this specific use case?

export const useTimer = () => {
  const [timer, setTimerObject] = useState<NodeJS.Timeout | null>(null);
  //HERE THE IMMUTABLE STATE OBJECT
  const [functions] = useState({
    setTimer : (callback:(...args:any[])=>void,ms:number)=>{
      setTimerObject(setTimeout(callback,ms))
    },
    clearTimer : ()=>{
      setTimerObject(null)
    }
  });
  
  //shouldComponentUpdate: delete previous timer if a new timer is issued
  //work also as componentWillUnmount
  useEffect(() => {
    return () => {
      if (timer) clearTimeout(timer)
    }
  }, [timer])


  return functions;
}

推荐答案

尝试这样的事情

const useTimer = () => { 
    const ref = useRef({ 
      setTimer: function setTimer(callback:(...args:any[])=>void,ms:number){ 
        setTimerObject(setTimeout(callback,ms)) 
      },
      clearTimer: function clearTimer(){ 
        setTimerObject(null);
      } 
    }); 
    return ref.current; 
}

这篇关于自定义钩子:不可变的 useState 来存储函数并避免无限循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆