尽管标题行很短,但我对下面的示例有一些相关的问题,这些问题借自 React 官方文档。我对原始样本进行了一些修剪。
在第一次
App
渲染时(当页面第一次加载时),usePointerPosition
钩子会注册一个 pointermove
侦听器。
useEffect
体内的usePointerPosition
还没有运行。
<Dot>
JSX 从 App
返回,位置为 {0, 0}
。
问题:移动鼠标时会发生什么?哪个代码触发渲染:
usePointerPosition
钩子,还是 App
组件?
我可能不正确和不完整的理解是:
鼠标移动会触发
handleMove
监听器。
此监听器更新
position
钩子中的状态 usePointerPosition
。
问题: 由于
position
是 usePointerPosition
钩子的私有状态,为什么它会导致其父级 App
重新渲染,这显然是重新渲染,因为我确实看到了红色 Dot
在屏幕上移动?
我可以看到私有状态
position
正在返回到usePointerPosition
钩子的父级App
。但是因为 pos1
中的 App
存储当前鼠标位置,它不是 App
中的状态,而只是一个局部变量,为什么当我移动鼠标时 App
会重新渲染自身?
问题: 一般来说,是一些自定义的非GUI钩子,
useXyz
...
a.仅通过在其主体中使用
useState
来保持私有状态;
b.不通过传递给它的回调与其父级交互 通过道具;和
c.体内没有
useEffect
...能够触发其父组件的渲染?
import React, { useEffect, useState } from 'react'
export default function App() {
const pos1 = usePointerPosition()
const pos2 = useDelayedValue(pos1, 100)
return (
<>
<Dot position={pos1} opacity={1} />
</>
)
}
function usePointerPosition() {
const [position, setPosition] = useState({ x: 0, y: 0 })
useEffect(() => {
function handleMove(e) {
setPosition({ x: e.clientX, y: e.clientY })
}
window.addEventListener('pointermove', handleMove)
return () => window.removeEventListener('pointermove', handleMove)
}, [])
return position
}
function useDelayedValue(value, delay) {
// TODO: Implement this Hook
return value
}
function Dot({ position, opacity }) {
return (
<div
style={{
position: 'absolute',
backgroundColor: 'pink',
borderRadius: '50%',
opacity,
transform: `translate(${position.x}px, ${position.y}px)`,
pointerEvents: 'none',
left: -20,
top: -20,
width: 40,
height: 40
}}
/>
)
}
Hooks的本质是挂在Fiber节点上的副作用。
所以当你调用
useState
时,它会创建一个副作用节点并挂在App
的纤程节点上,调用setPosition
将重新渲染App