Javascript 使用React钩子实现一个自增量计数器

Javascript 使用React钩子实现一个自增量计数器,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,代码如下: 导出默认值({name}:Props)=>{ const[counter,setCounter]=useState(0); useffect(()=>{ 常量间隔=设置间隔(()=>{ 设置计数器(计数器+1); }, 1000); return()=>{ 间隔时间; }; }); 返回{counter}; }; 问题是每个setCounter触发器都会重新渲染,因此间隔会被重置并重新创建。这看起来很好,因为状态(计数器)一直在增加,但是当与其他挂钩组合时,它可能会冻结 正确的方法

代码如下:

导出默认值({name}:Props)=>{
const[counter,setCounter]=useState(0);
useffect(()=>{
常量间隔=设置间隔(()=>{
设置计数器(计数器+1);
}, 1000);
return()=>{
间隔时间;
};
});
返回{counter};
};
问题是每个
setCounter
触发器都会重新渲染,因此间隔会被重置并重新创建。这看起来很好,因为状态(计数器)一直在增加,但是当与其他挂钩组合时,它可能会冻结


正确的方法是什么?在类组件中,使用实例变量保持间隔非常简单。

您可以将空数组作为第二个参数提供给
useffect
,这样函数在初始渲染后只运行一次。由于闭包的工作方式,这将使
计数器
变量始终引用初始值。然后,您可以使用函数版本的
setCounter
来始终获得正确的值

示例

const{useState,useffect}=React;
函数App(){
const[counter,setCounter]=useState(0);
useffect(()=>{
常量间隔=设置间隔(()=>{
设置计数器(计数器=>计数器+1);
}, 1000);
return()=>{
间隔时间;
};
}, []);
返回{counter};
};
ReactDOM.render(
,
document.getElementById('root'))
);

如前所述,可以使其
useffect
回调只运行一次,并与
componentDidMount
类似。在这种情况下,由于函数作用域的限制,有必要使用状态更新程序函数,否则更新的
计数器
setInterval
回调中不可用

另一种方法是在每次计数器更新时运行
useffect
回调。在这种情况下,
setInterval
应替换为
setTimeout
,更新应限于
计数器
更新:

export default ({ name }: Props) => {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
    const timeout = setTimeout(() => {
      setCounter(counter + 1);
    }, 1000);

    return () => {
      clearTimeout(timeout);
    };
  }, [counter]);

  return <h1>{counter}</h1>;
};
导出默认值({name}:Props)=>{
const[counter,setCounter]=useState(0);
useffect(()=>{
常量超时=设置超时(()=>{
设置计数器(计数器+1);
}, 1000);
return()=>{
clearTimeout(超时);
};
},[柜台];
返回{counter};
};

正确的方法是只运行一次效果。因为在装载过程中,只需要运行一次效果,所以可以将空数组作为第二个参数传入以实现

但是,您需要更改
设置计数器
以使用先前的
计数器值
。原因是传递到
setInterval
闭包中的回调仅在第一次渲染中访问
计数器
变量,在随后的渲染中,它无法访问新的
计数器
值,因为第二次未调用
useffect()
<代码>计数器
设置间隔
回调中始终具有值0

与您熟悉的
setState
一样,状态挂钩有两种形式:一种是在更新状态下使用,另一种是在其中传递当前状态的回调形式。您应该使用第二种形式并读取
setState
回调中的最新状态值,以确保在递增之前具有最新状态值

函数计数器(){
const[counter,setCounter]=React.useState(0);
React.useffect(()=>{
常量计时器=设置间隔(()=>{
设置计数器(prevCount=>prevCount+1);//{
清除间隔(计时器);
};
},[]);//传入空数组仅运行一次效果!
返回(
计数:{counter}
);
}
ReactDOM.render(,document.querySelector(“#app”);


这并不理想,因为每次渲染时都会运行
setTimeout
,这似乎是不必要的。我看不出这有什么问题。性能问题不存在。递归setTimeout是JS中setInterval的常用替代品,只要它是合理的。在这个特定的c中,setInterval中的状态更新程序函数看起来不错ase,即简单增量。如果涉及多个状态,这将非常不同。
export default ({ name }: Props) => {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
    const timeout = setTimeout(() => {
      setCounter(counter + 1);
    }, 1000);

    return () => {
      clearTimeout(timeout);
    };
  }, [counter]);

  return <h1>{counter}</h1>;
};