reactjs React在re-render后调用ref回调时如何清除旧的ref?

2fjabf4q  于 2023-05-28  发布在  React
关注(0)|答案(6)|浏览(299)

bounty还有2天到期。此问题的答案有资格获得+50声望奖励。user31782正在寻找这个问题的更详细的答案

正如React文档中提到的:
如果ref回调被定义为一个内联函数,它将在更新期间被调用两次,第一次使用null,然后再次使用DOM元素。这是因为每次render都会创建一个新的函数示例,所以React需要清除旧的ref并设置新的。
我可以理解el被设置为null,因为我们需要在重新渲染后释放旧的dom节点的内存。但有两个问题我还是想不通。
1.为什么React必须首先在这里使用null调用旧的ref回调?难道它不能用新的dom节点调用新的ref回调函数吗?

  1. React如何清除旧的ref?这和调用ref回调两次有关吗?
ifmq2ha2

ifmq2ha21#

你可以 * 考虑 * ref为callback ref重置作为一种效果。不是这样的,但我认为重新措辞的问题确实有助于理解。

useEffect(() => {
  ref.current = element

  return () => {
    ref.current = null
  }
})

假设你将ref回调传递给一个DOM节点:

<div ref={(element) => console.log(element)} />

从效果的Angular 思考会给你:
1.当组件装入时,它将使用该元素调用ref回调
1.当组件卸载时,它调用ref回调函数null,因为这是“清理”
1.当组件改变时,它首先调用“cleanup”,然后设置新的“effect”。
同样,这是说它使用了真实的的useEffect,但其背后的思想是相同的。

piah890a

piah890a2#

当React调用ref回调时,它需要知道它是在设置一个新的ref还是在删除一个旧的ref。
通过使用null参数调用旧的ref回调,React向回调发出信号,表示应该清除对**前一个元素的引用。

uwopmtnx

uwopmtnx3#

示例代码:-

import React, { useRef, useEffect } from 'react'

const AudioPlayer = () => {
  const audioRef = useRef(null)

  useEffect(() => {
    if (audioRef.current) {
      audioRef.current.play()
    }

    return () => {
      if (audioRef.current) {
        audioRef.current.pause()
      }
    }
  }, [audioRef])

  return (
    <div>
      <video ref={audioRef} src="audio.mp3" controls />
    </div>
  )
}

以下是您问题的答案
1.通过首先使用null调用旧的ref回调,React为您提供了一个执行任何特定于旧DOM元素的清理或拆除逻辑的机会。在上面的示例中,在将新的audio元素分配给audioRef.current之前,调用useEffect内部的cleanup函数,允许我们使用audioRef.current.pause()暂停旧的audio元素

  1. React通过调用ref回调两次来清除旧的ref。第一个null调用有效地清除了对旧DOM元素的引用,表明它不再被那个特定的ref(audioRef)引用。这允许您执行任何必要的清理任务或释放与旧DOM元素关联的任何资源。第二次调用新DOM元素时,将ref分配给新DOM元素(audioRef.current = newElement),允许您访问和使用它。
aij0ehis

aij0ehis4#

如果你想改变ref并且在重新渲染时不变为null,有一个更简单的方法使用state而不是Ref。虽然这是不推荐的东西,如果你正在使用参考,但它会解决问题。

const [refElement, setRefElement] = useState(null)
  return (
    <div
    ref={(el)=>setRefElement(el)}
    />
    )
xuo3flqw

xuo3flqw5#

当React更新组件的渲染输出时,它可能会用新的DOM元素替换旧的DOM元素。为了处理这种变化,React在调用ref回调时遵循两步过程。
首先,React使用null调用旧的ref回调。这允许我们执行与前一个DOM元素相关的任何必要的清理操作。例如,我们可以删除事件侦听器,取消计时器或清理为旧元素设置的任何其他资源。null值表示旧元素正在被卸载,它给了我们一个释放与它关联的任何资源的机会。
在清理步骤之后,React再次调用ref回调,但这次使用新的DOM元素作为参数。在这里,您可以执行更新的元素所需的任何其他设置或操作。我们可以存储对新元素的引用或执行任何其他必要的任务。
简而言之,React首先使用null调用旧的ref回调,以允许与前一个DOM元素相关的清理操作。然后,它用新的DOM元素调用新的ref回调函数,以设置对更新后的元素的引用。这个两步流程确保我们有机会释放资源,并妥善处理新旧元素之间的过渡。

tv6aics1

tv6aics16#

React使用null调用旧的ref回调,让你有机会清理与旧DOM元素相关的任何资源。如果您有事件侦听器或对旧DOM元素的其他引用,则可以在设置新引用之前释放它们。
React通过以null作为参数调用ref回调来清除旧的ref,确保旧的DOM引用被删除。通过两次调用ref回调,React确保在设置新ref之前清理旧资源。第一个调用将旧的ref设置为null,第二个调用将新的DOM元素传递给ref回调。此过程允许您正确管理新旧参照之间的转换。

相关问题