6

我对这一点感到困惑React.forwardRef。正如其文档中所解释的,我知道它的主要用途是让父组件访问子组件的DOM元素。但我已经可以做到这一点,甚至不必使用它。

这是一个代码示例,您可以将其插入 CodeSandbox 并查看它是否有效:

import React, {useRef, useEffect} from "react";
import "./styles.css";

const ChildComponent = (props) => {

  useEffect( ()=> {
    props.callbackFunction()
  })

  return(
    <div ref={props.fRef}>
      {"hello"}
    </div>
  )
}


export default function App() {
  const callbackFunction = () => {
    console.log("The parent is now holding the forwarded ref to the child div: ")
    console.log(forwardedRef)
  }

  const forwardedRef = useRef(null)

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <ChildComponent name="gravy" callbackFunction={callbackFunction} fRef={forwardedRef}/>
    </div>
  );
}

或者这里是这个例子的嵌入。老实说,我对此有点陌生,我不知道嵌入是如何工作的,也不知道有人摆弄嵌入是否会改变我原来的沙箱,所以我犹豫不决。但在这里。 示例转发参考

在示例中,父App()组件成功地将 ref 传递给子组件,子组件将其附加到其呈现的div。渲染后,它会向父级调用回调函数。然后父级执行控制台日志,证明其转发的 ref 现在拥有子级的 div。而这一切都是在没有React.forwardRef.

那么有什么用React.forwardRef呢?

4

2 回答 2

8

你完全正确,你可以做你所描述的。缺点是您被迫公开一个 API(即:fRef道具)以使其工作。如果您是构建应用程序的独立开发人员,这没什么大不了的,但它可能会出现更多问题,例如。如果您使用公共 API 维护开源库。

在这种情况下,库的使用者将无法访问组件的内部,这意味着您必须以某种方式为他们公开它。您可以简单地按照您在示例中的建议进行操作并添加一个命名道具。事实上,这就是 React 16.3 之前的库所做的。没什么大不了的,但您必须记录它,以便人们知道如何使用它。理想情况下,您还需要某种每个人都使用的标准,这样就不会造成混淆(许多库都使用innerRef命名约定),但必须对此达成一些共识。所以一切都是可行的,但也许不是理想的解决方案。

使用forwardRef,将 ref 传递给组件就像预期的那样工作。prop 已经在 React中ref标准化,因此您无需查看文档即可了解如何向下传递 ref 或它是如何工作的。但是,您描述的方法完全可以,如果它满足您的需求,请务必使用。

于 2020-03-31T23:57:00.743 回答
2

文档中所述,它对于高度可重用的组件很有用,这意味着组件倾向于像常规 HTML DOM 元素一样使用。

这对于拥有大量“叶子”组件的组件库很有用。您可能已经使用过 Material UI。

例子:

假设您正在维护一个组件库。

您创建一个组件<Button/><Input/>它可能只是添加了一些默认样式。

请注意,这些组件实际上就像带有额外步骤的常规 HTML DOM 元素一样。

如果这些组件被制作成像常规 HTML DOM 元素一样使用,那么我希望所有道具都是相同的,包括ref,不是吗?

<Button/>如果从您的组件中获取按钮引用,我必须通过类似的东西来获取它,这fRef不是很乏味buttonRef吗?

与您的一样<Input/>,我是否必须去文档才能找出要使用的 ref 和类似的东西inputRef?现在我必须记住吗?

获取 ref 应该很简单<Button ref={}/>

问题

你可能知道,ref不会通过 props 传递,因为keyReact 对它的处理方式不同。

解决方案

React.forwardRef() 解决了这个问题,所以我可以使用<Button ref={}/>or <Input ref={}/>

于 2020-04-01T00:40:18.917 回答