我想表达我对钩子的担忧。
出于学习目的,使用钩子重构/重写React库(react-numpad)的过程中,我一直坚持在关键事件上使用eventListener实现。
使用类,只需在componentDidMount和componentWillUnmount生命周期内添加addListener即可实现。
useKeyPress挂钩
更新回调
NumPad组件是具有值状态的父级
挂钩使用情况
键盘组件是接收值作为道具并调用的子级 更新keydown作为回调。如果useEffect(在挂钩内)具有空数组,则不会更新此值
现在在每个渲染器上添加和删除addListener。这不是以前发生的,只有在安装或卸载组件时才发生。
使用钩子与使用类有相同的行为吗?
答案 0 :(得分:1)
您不需要在每个渲染器中添加或删除事件侦听器,并且完全可以像以前一样添加一次事件侦听器,方法是使用useEffect并将空数组用作第二个参数。像这样:
useEffect(() => {
// your didMount code here
return () => {
// your willUnmount code here
}
}, [])
这样做的问题是,由于该函数仅运行一次,因此更改后无法更新其可访问的值(例如props或其他外部作用域变量)。
例如:
const [foo, setFoo] = setState(1)
useEffect(() => {
const id = window.setInterval(() => console.log(foo), 1000)
return () => window.clearInterval(id)
}, [])
// ...
setFoo(2)
即使调用setFoo之后,此代码也将始终显示1,因为该函数已绑定到foo的旧值。
当您只需要根据自身和其他值继续更新某些状态时,最好的选择是使用带有useReducer的reducer。您可以从useEffect函数(或任何其他位置)使用dispatch,然后将以已更新状态调用reducer,从而允许其读取并根据需要对其进行更新。只需传递有关动作本身的任何新信息即可。
在您使用的情况下,您只需调度相关的事件信息,并让化简处理更新。
如果您可以使用标准的react事件而不是任何addEventListener,则不必考虑这一点,因为该函数将在每个渲染器上更新,而无需您执行任何操作。您可以将函数作为道具传递,以便它们也可以从子组件中使用。
您可以改用ref,因为它们总是返回相同的对象,对它进行突变而不是创建一个新的对象。这使得具有访问引用的功能都可以读取当前值。
示例:
const fooRef = useRef(1)
fooRef.current = foo
useEffect(() => {
const id = window.setInterval(() => console.log(fooRef.current), 1000)
return () => window.clearInterval(id)
}, [])
// ...
fooRef.current = 2
您可以将ref用作值,甚至可以将其用于要从事件处理程序调用的函数。这不是更干净的路径,但是您可以使其正常工作。