useState中的 State不改变



我有一个功能组件

import React, { useState } from 'react'
export default function AboutUs() {
const [counter,setCounter] = useState(0);
const clicked = () => {
setCounter(counter+1);
}
return (
<div>
<p>you clicked {counter} times</p>
<button onClick={clicked}>Click</button>        
</div>
)
}

没有什么问题,它工作得很好。但是当我删除onClick in按钮元素并添加事件侦听器时,如:

import React, { useEffect, useState } from 'react'
export default function AboutUs() {
const [counter,setCounter] = useState(0);
useEffect(()=>{
document.getElementById('test').addEventListener('click',clicked);
},[])
const clicked = () => {
setCounter(counter+1);
}
return (
<div>
<p>you clicked {counter} times</p>
<button id="test">Click</button>        
</div>
)
}

一键后计数器Value将为1,然后停止!柜台setCounter了!这有什么不对吗?我很感激你的帮助。

我有一个功能组件

你没有。

组件跟踪状态违反了函数式编程的原则,即函数应该具有无副作用.

你有一个函数组件.


计数器不再被setCounter改变!

事件处理程序附加在useEffect钩子中。

当组件第一次挂载或任何依赖项发生变化时,该钩子被调用。

依赖项列表是[],所以依赖项永远不会改变。

每次调用它(我们刚刚建立的只有一次),它将创建一个函数,关闭counter常数(最初设置为0)

每次点击该元素时,你会得到setCounter(counter+1);,而counter总是0,因为这是被关闭的常量的值。

(尽管改变状态会触发重新渲染,这会创建一个同名的不同的常量)) .


要使用这种方法,您通常会这样做:

useEffect(()=>{
document.getElementById('test').addEventListener('click',clicked);
return () => document.getElementById('test').removeEventListener('click', 'clicked');
},[clicked])

所以每次函数更改时,它都会清除以前的事件侦听器并添加新的事件侦听器(它已经关闭了新的常量)


但是直接的DOM操作是脆弱的,并且丢掉了React的主要优点。所以不要这么做。使用onClick={click}方法,这就是React的设计工作方式。

这里有两个问题:

  1. useEffect依赖项未指定
  2. useEffect没有清理处理程序更新你的代码会得到这样的东西:
useEffect(() => {
const element = document.getElementById('test');
element.addEventListener('click', clicked);
return () => { element.removeEventListener('click', clicked) };
}, [clicked]);

但是一个问题仍然存在:clicked函数引用在每次渲染时都会改变,这意味着useEffect将在每次渲染时删除/添加侦听器。为了避免这种情况,您应该将单击的处理程序包装在useCallback中,并使用适当的依赖项,如下所示:

const clicked = useCallback(() => {
setCounter(counter + 1);
}, [counter]);

最新更新