我一生无法知道发生了什么,但是由于某些原因,当单击“单击我”时,数字会按预期增加。当子组件触发点击时,它将重置状态并始终打印0。
function Child(props: {
onClick?: (id: string) => void,
}) {
const ref = useCallback((ref) => {
ref.innerHTML = 'This Doesnt';
ref.addEventListener('click',() => {
props.onClick!('')
})
}, [])
return (<div ref={ref}></div>)
}
function Parent() {
const [number, setNumber] = useState(0);
return <div>
<div onClick={() => {
setNumber(number + 1);
console.log(number);
}}>
This Works
</div>
<Child
onClick={(id) => {
setNumber(number + 1);
console.log(number);;
}}
/>
</div>
}
答案 0 :(得分:2)
正确地在每个渲染器上重新创建父组件中的onClick
处理程序,因为它们在number
状态字段上具有关闭符。
问题是,发送到Child组件的onClick
属性在ref
回调中使用,由于依赖列表为空,因此仅在初始渲染期间做出了反应。因此,Child在后续渲染中收到的onClick
道具根本无法使用。
尝试通过删除依赖项参数或发送props.onClick来解决此错误,如依赖项列表中所述,由于文档中提到的警告,我们陷入了困境。 https://reactjs.org/docs/refs-and-the-dom.html
因此,您添加了空处理,并且现在看到更新的回调正在被调用,但是...由于我们尚未删除这些事件侦听器,因此也会调用所有更早的回调。
const ref = useCallback((ref) => {
if(!ref) return;
ref.innerHTML = 'This Doesnt';
ref.addEventListener('click',() => {
props.onClick!('')
})
}, [props.onClick])
我认为,这只是作为学习挂钩的一部分而进行的实验,否则,无需采取round回的方式从ref回调中调用onClick
。只需将它作为道具传递给div
。
修改:
根据您的评论,由于这不仅是实验,而且还简化了一些真正的要求(需要通过addEventListener
设置点击处理程序),因此可以采用以下解决方案:
const ref = useRef(null);
useEffect(() => {
if(!ref.current) return;
ref.current.innerHTML = 'This Doesnt';
const onClick = () => props.onClick!('');
ref.current.addEventListener('click',onClick)
// return the cleanup function to remove the click handler, which will be called before this effect is run next time.
return () => {ref.current.removeEventListener("click", onClick)}
}, [ref.current, props.onClick]);
基本上,我们需要使用useEffect
,以便我们有机会在添加新的监听器之前先删除旧的监听器。
希望这会有所帮助。
答案 1 :(得分:1)
ip=192.168.1.100::192.168.1.1:255.255.255.0::eth0
@ckder几乎可以使用,但是console.log显示了从0到当前数字值的所有数字。 事件侦听器的问题在于卸载子组件之后尚未删除事件侦听器,因此要达到此目的,我在卸载侦听器的地方使用了useEffect和return函数。