理解:警告:函数组件不能被赋予refs。

21
我知道 refs 用于直接访问 DOM 元素而不更改状态。我读到过不能给函数组件提供 refs,因为它们没有状态。
引用无法附加到函数组件。虽然我们可以定义 refs 并将其附加到 DOM 元素或类组件。底线是 - 函数组件没有实例,所以你不能引用它们。
摘自:https://blog.logrocket.com/cleaning-up-the-dom-with-forwardref-in-react/ 我仍然不明白。
我正在使用 Ant Design 的 Tooltip 组件(https://ant.design/components/tooltip/),Button 组件和自定义 CircleButton 组件。
给出以下 JSX:
<Tooltip placement="left" title={"Lock slot"}>
  <CircleButton onClick={() => execute(client.close)} icon={<LockOutlined />} disabled={loading} />
</Tooltip>

还有我的CircleButton组件。如果像这样使用它,将会生成警告。

const CircleButton = (props) => // gives the warning
  <Button shape="circle" size="small" style={{ marginRight: "8px" }} {...props} />

警告:无法为函数组件赋予ref。尝试访问此ref将失败。您是否意味着使用React.forwardRef()?

请注意,尽管出现警告,但一切均按预期工作。

如果我按以下方式进行编辑,它会正常工作,为什么?

const CircleButton = forwardRef((props, ref) => // doesn't give the warning
  <div ref={ref}>
    <Button shape="circle" size="small" style={{ marginRight: "8px" }} {...props} />
  </div>)

div组件有状态吗?我不明白。是forwardRef在为

元素创建状态吗?

那么,如果我将ref传递给Button组件,为什么它仍然会出现警告?

const CircleButton = forwardRef((props, ref) => // gives the warning
  <Button ref={ref} shape="circle" size="small" style={{ marginRight: "8px" }} {...props} />)

如果我直接将antdButton作为子元素传递,它是可以工作的。但这是因为我认为 antd按钮具有状态,因此可以拥有refs。
<Tooltip placement="left" title={"Lock slot"}> // doesn't give the warning
  <Button shape="circle" size="small" style={{ marginRight: "8px" }} />
</Tooltip>

一个不同的用例,但是类似的错误信息:https://dev59.com/q1MI5IYBdhLWcg3wUp42#69767229 - KeshavDulal
这里我解释一下为什么会出现这个警告,举一个类似的例子是关于 input 元素的,这个例子帮助我完全理解了它:https://dev59.com/h8X5oIgBc1ULPQZF3D4_#73567453 - Andru
2个回答

9
正如警告所述,如果不使用forwardRef,则无法将refs分配给函数式组件。
为了访问任何组件的refs,必须创建该组件的实例,而且只有类组件才会创建实例,而函数式组件只是被调用或者说是执行。
从版本16.8.0开始,React引入了一个API叫做useRef,它允许您在函数式组件中创建refs,并且这些refs可以用于HTML节点、类组件或使用forwardRef包装的函数式组件。
此外,为了实现在类组件中使用ref时可用的相同行为,您可以使用forwardRefuseImperativeHandle hook来向父组件公开函数或状态。
const CircleButton = forwardRef((props, ref) => {
  const someFunction = () =>{}
  useImperativeHandle(ref, () => ({
     someFunc
  }));

  return (
    <div>
        <Button shape="circle" size="small" style={{ marginRight: "8px" }} {...props} />
   </div>

  )
}

5
不要混淆,首先这与功能或类组件问题无关,这意味着您可以为两者都使用引用,React 16+具有钩子useRef,因此您也可以为函数组件使用引用。
回答您的问题,antd Button有自己的引用,因此在您的情况下省略了父组件传递的引用Tooltip,这就是为什么您没有看到任何警告的原因,但当您使用自己的组件时,您必须考虑Tooltip传递的ref
而且,如果您仍然不想使用React.forwordRef,那么在向组件传递props时只需忽略它即可。但是,您将不会获得antd受控组件提供的某些特权功能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接