Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何防止内联函数绑定到旧状态值_Javascript_Reactjs_React Hooks - Fatal编程技术网

Javascript 如何防止内联函数绑定到旧状态值

Javascript 如何防止内联函数绑定到旧状态值,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,在使用挂钩的React组件的项目中,我试图理解如何正确地避免调用绑定到旧状态值的回调。下面的示例说明了这个问题(但不是我正在处理的代码) import React,{useState,useffect}来自“React”; 从“react dom”导入react dom; 常量消息=()=>{ const[message,setMessage]=useState(“”); 函数doStuff(){ 控制台日志(消息); } useffect(()=>{ 设定间隔(doStuff,1000) },

在使用挂钩的React组件的项目中,我试图理解如何正确地避免调用绑定到旧状态值的回调。下面的示例说明了这个问题(但不是我正在处理的代码)

import React,{useState,useffect}来自“React”;
从“react dom”导入react dom;
常量消息=()=>{
const[message,setMessage]=useState(“”);
函数doStuff(){
控制台日志(消息);
}
useffect(()=>{
设定间隔(doStuff,1000)
}, []);
返回(
setMessage(e.target.value)}
/>

{message}

); }; const rootElement=document.getElementById(“根”); render(,rootElement);
这里的问题当然是
setInterval
将保持
doStuff
函数在第一次(也是唯一一次)调用效果时的状态。此时,
消息
状态为空,因此,interval函数将每秒打印一个空字符串,而不是文本框中的消息

在我的实际代码中,我遇到了应该触发组件内部函数调用的外部事件,它们也遇到了同样的问题


我该怎么办?

您应该
使用callback
并将其作为依赖项传递给您

const doStuff = useCallback(() => {
  console.log(message);
}, [message]);

useEffect(() => {
  const interval = setInterval(doStuff, 1000);
  return () => clearInterval(interval); // clean up
}, [doStuff]);


在这里,当
消息
得到更新时,它将在
doStuff
中有新的值,您也可以将其放入自己的钩子中。我的生产代码中有这个

/**
 * A react hook for setting up an interval
 * @param handler - Function to execute on interval
 * @param interval - interval in milliseconds
 * @param runImmediate - If the function is executed immediately
 */
export const useInterval = (handler: THandlerFn, interval: number | null, runImmediate = false): void => {
  const callbackFn = useRef<THandlerFn>()

  // Update callback function
  useEffect((): void => {
    callbackFn.current = handler
  }, [handler])

  // Setup interval
  useEffect((): (() => void) | void => {
    const tick = (): void => {
      callbackFn.current && callbackFn.current()
    }

    let timerId: number
    if (interval) {
      if (runImmediate) {
        setTimeout(tick, 0)
      }

      timerId = setInterval(tick, interval)

      return (): void => {
        clearInterval(timerId)
      }
    }
  }, [interval, runImmediate])
}
/**
*用于设置间隔的反应钩
*@param handler-按间隔执行的函数
*@param interval-以毫秒为单位的间隔
*@param runImmediate-如果函数立即执行
*/
export const useInterval=(处理程序:THandlerFn,间隔:number | null,runImmediate=false):void=>{
const callbackFn=useRef()
//更新回调函数
useffect(():void=>{
callbackFn.current=处理程序
},[handler])
//设置间隔
useEffect(():(()=>void)| void=>{
常量勾号=():无效=>{
callbackFn.current&&callbackFn.current()
}
让我们看看这个数字
如果(间隔){
如果(立即运行){
设置超时(勾选,0)
}
timerId=setInterval(勾选,间隔)
return():void=>{
清除间隔(timerId)
}
}
},[interval,runImmediate])
}

不过需要注意的是,这与清除每次消息更新的间隔基本相同。因此,如果你更新消息太频繁,间隔不会触发。我的实际代码不包含间隔,我只是选择它来获得尽可能小的示例。我会调查的。谢谢
/**
 * A react hook for setting up an interval
 * @param handler - Function to execute on interval
 * @param interval - interval in milliseconds
 * @param runImmediate - If the function is executed immediately
 */
export const useInterval = (handler: THandlerFn, interval: number | null, runImmediate = false): void => {
  const callbackFn = useRef<THandlerFn>()

  // Update callback function
  useEffect((): void => {
    callbackFn.current = handler
  }, [handler])

  // Setup interval
  useEffect((): (() => void) | void => {
    const tick = (): void => {
      callbackFn.current && callbackFn.current()
    }

    let timerId: number
    if (interval) {
      if (runImmediate) {
        setTimeout(tick, 0)
      }

      timerId = setInterval(tick, interval)

      return (): void => {
        clearInterval(timerId)
      }
    }
  }, [interval, runImmediate])
}