如何在道具更改时更新状态,而无需渲染两次
How to update a state when a prop changes, without rendering twice
我有一个数据可视化组件,它以“宽度”作为道具之一。状态跟踪图表中的缩放级别,并在处理鼠标事件时更新。
当宽度改变时缩放需要调整。目前,我在 useEffect 挂钩中执行此操作:
function MyComponent({width}) {
const [zoom, setZoom] = useState(...)
useEffect(() => {
setZoom(adjustZoom(zoom, width))
}, [width])
const handleMouseEvent = (event) => {
setZoom(calculateNewZoom(event))
}
...
}
但这会使组件渲染两次:一次用于宽度更新,一次用于缩放更新。由于第一个渲染在屏幕上闪烁,因此并不理想。
理想情况下,组件只渲染一次,同时反映宽度和缩放的变化。如何用钩子实现这一点?另外,这个概念有名称吗?提前致谢。
Since the first render flashes on screen, it is not ideal.
这就是 useLayoutEffect()
旨在解决的问题,作为 useEffect()
的直接替代。
你还有另一个潜在的问题,那就是你的 useEffect()
包含 setZoom()
的 stale reference to zoom
. In order to obtain the correct reference, use the functional update 形式:
function MyComponent({ width }) {
const [zoom, setZoom] = useState(...)
useLayoutEffect(() => {
setZoom((zoom) => adjustZoom(zoom, width))
}, [width])
const handleMouseEvent = (event) => {
setZoom(calculateNewZoom(event))
}
...
}
或者,您可以考虑删除 useLayoutEffect()
和 using a memoized adjustedZoom
以避免双重呈现:
function MyComponent({ width }) {
const [zoom, setZoom] = useState(...)
const adjustedZoom = useMemo(() => {
return adjustZoom(zoom, width)
}, [zoom, width])
const handleMouseEvent = (event) => {
setZoom(calculateNewZoom(event))
}
...
// now use adjustedZoom where you would have used zoom before
}
我有一个数据可视化组件,它以“宽度”作为道具之一。状态跟踪图表中的缩放级别,并在处理鼠标事件时更新。
当宽度改变时缩放需要调整。目前,我在 useEffect 挂钩中执行此操作:
function MyComponent({width}) {
const [zoom, setZoom] = useState(...)
useEffect(() => {
setZoom(adjustZoom(zoom, width))
}, [width])
const handleMouseEvent = (event) => {
setZoom(calculateNewZoom(event))
}
...
}
但这会使组件渲染两次:一次用于宽度更新,一次用于缩放更新。由于第一个渲染在屏幕上闪烁,因此并不理想。
理想情况下,组件只渲染一次,同时反映宽度和缩放的变化。如何用钩子实现这一点?另外,这个概念有名称吗?提前致谢。
Since the first render flashes on screen, it is not ideal.
这就是 useLayoutEffect()
旨在解决的问题,作为 useEffect()
的直接替代。
你还有另一个潜在的问题,那就是你的 useEffect()
包含 setZoom()
的 stale reference to zoom
. In order to obtain the correct reference, use the functional update 形式:
function MyComponent({ width }) {
const [zoom, setZoom] = useState(...)
useLayoutEffect(() => {
setZoom((zoom) => adjustZoom(zoom, width))
}, [width])
const handleMouseEvent = (event) => {
setZoom(calculateNewZoom(event))
}
...
}
或者,您可以考虑删除 useLayoutEffect()
和 using a memoized adjustedZoom
以避免双重呈现:
function MyComponent({ width }) {
const [zoom, setZoom] = useState(...)
const adjustedZoom = useMemo(() => {
return adjustZoom(zoom, width)
}, [zoom, width])
const handleMouseEvent = (event) => {
setZoom(calculateNewZoom(event))
}
...
// now use adjustedZoom where you would have used zoom before
}