使用 react-router-dom 时如何避免“功能组件不能被赋予 refs”?

Posted

技术标签:

【中文标题】使用 react-router-dom 时如何避免“功能组件不能被赋予 refs”?【英文标题】:How do I avoid 'Function components cannot be given refs' when using react-router-dom? 【发布时间】:2019-10-22 09:25:06 【问题描述】:

我有以下(使用 Material UI)....

import React from "react";
import  NavLink  from "react-router-dom";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
function LinkTab(link)
    return <Tab component=NavLink
        to=link.link
        label=link.label
        value=link.link
        key=link.link
    />;

在新版本中,这会导致以下警告...

警告:函数组件不能被赋予 refs。尝试访问 这个裁判会失败。你的意思是使用 React.forwardRef() 吗?

检查ForwardRef的渲染方法。 在 NavLink 中(由 ForwardRef 创建)

我试着改成...

function LinkTab(link)
    // See https://material-ui.com/guides/composition/#caveat-with-refs
    const MyLink = React.forwardRef((props, ref) => <NavLink ...props ref=ref />);
    return <Tab component=MyLink
        to=link.link
        label=link.label
        value=link.link
        key=link.link
    />;

但我仍然收到警告。我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

来自react-routerNavLink 是一个函数组件,它是Link 的专用版本,它为此目的公开了一个innerRef 属性。

// required for react-router-dom < 6.0.0
// see https://github.com/ReactTraining/react-router/issues/6056#issuecomment-435524678
const MyLink = React.forwardRef((props, ref) => <NavLink innerRef=ref ...props />);

您还可以在我们的文档中搜索 react-router,这会将您引导至链接到 https://mui.com/components/buttons/#third-party-routing-library 的 https://mui.com/getting-started/faq/#how-do-i-use-react-router。最后一个链接提供了一个工作示例,并解释了这在 react-router v6 中可能会如何变化

【讨论】:

如果我们有来自 react-router-hash-link 的哈希链接呢? 如果你根本不使用 react-router 怎么样?你如何使用 forwardRef 和同样的警告? 这个链接帮助我解决问题 [blog.jscrambler.com/…【参考方案2】:

您好,您可以使用 refs 代替 ref

    <InputText
        label="Phone Number"
        name="phoneNumber"
        refs=register( required: true )
        error=errors.phoneNumber ? true : false
        icon=MailIcon
   />

【讨论】:

你好。你能解释一下 ref 和 refs 之间的区别吗?我查看了 React 文档,但找不到任何对 refs=(复数)的引用。这对我很有用,但想了解它在功能组件上的工作原理。谢谢。 并不是特指refs。只是道具“ref”是一个特殊的道具(就像“key”一样)。您可以将其传递为“foo”而不是“refs”,它也可以工作。 正如@FilipeValente 所说,它不是任何特定的参考。它只是充当道具, 我发现自己也在质疑 refs 是否是一个特殊的道具,所以我选择了 innerRef 只是因为它的作用更清晰一些。【参考方案3】:

只要给它innerRef

// Client.js
<Input innerRef=inputRef />

将其用作ref

// Input.js
const Input = ( innerRef ) => 
  return (
    <div>
      <input ref=innerRef />
    </div>
  )

【讨论】:

就这么简单——我发现这是最容易理解的。 @Hasan 认真的吗?这实际上有效,并且没有像其他答案中提到的那样涉及任何重大变化。 如果可行,为什么forwardRef 存在? 魔法!就像将它从 ref 更改为 innerRef 一样简单【参考方案4】:
const renderItem = ( item, index ) => 

        return (
            <>          
            <Item
                key=item.Id
                item=item
                index=index
            />
            </>
        );
    ;

使用 Fragment 解决 React.forwardRef()?警告

【讨论】:

【参考方案5】:

如果您发现无法将自定义 ref 属性或 forwardRef 添加到组件中,我有一个技巧仍然可以为您的功能组件获取 ref 对象。

假设您想将 ref 添加到自定义功能组件,例如:

 const ref = useRef();

 //throws error as Button is a functional component without ref prop
 return <Button ref=ref>Hi</Button>;

您可以将其包装在一个通用的 html 元素中并在其上设置ref

 const ref = useRef();

 // This ref works. To get button html element inside div, you can do 
 const buttonRef = ref.current && ref.current.children[0];
 return (
  <div ref=ref>
   <Button>Hi</Button>
  </div>
 );

当然要相应地管理状态以及您想在哪里使用 buttonRef 对象。

【讨论】:

【参考方案6】:

要解决此警告,您应该使用 forwardRef 函数包装您的自定义组件,正如 blog 中提到的那样非常好

    const AppTextField =(props) return(/*your component*/)

以下代码改为

const AppTextField = forwardRef((props,ref) return(/*your component*/)

【讨论】:

【参考方案7】:

在我们的例子中,我们将一个 SVG 组件(网站的徽标)直接传递给 NextJS 的 Link Component,这有点定制,我们遇到了这样的错误。

使用 SVG 并“导致”问题的标题组件。

import Logo from '_public/logos/logo.svg'
import Link from '_components/link/Link'

const Header = () => (
  <div className=s.headerLogo>
    <Link href='/'>
      <Logo /> 
    </Link>
  </div>
)

控制台上的错误消息

Function components cannot be given refs. Attempts to access this ref will fail.
Did you mean to use React.forwardRef()?

自定义链接组件

import NextLink from 'next/link'
import  forwardRef  from 'react'

const Link = ( href, shallow, replace, children, passHref, className , ref) => 
  return href ? (
    <NextLink
      href=href
      passHref=passHref
      scroll=false
      shallow=shallow
      replace=replace
      prefetch=false
      className=className
    >
      children
    </NextLink>
  ) : (
    <div className=className>children</div>
  )


export default forwardRef(Link)

现在我们确定我们在自定义的链接组件中使用了 forwardRef,但我们仍然遇到了这个错误。

为了解决这个问题,我把SVG元素的wrapper定位改成了this和:poof:

const Header = () => (
  <Link href='/'>
    <div className=s.headerLogo>
      <Logo />
    </div>
 </Link>
)

【讨论】:

在创建自定义下一个链接组件时遇到了类似的问题,该组件基本上是围绕样式文本组件的包装器 - 通过在包装组件周围添加片段而不是 div 解决了这个问题。

以上是关于使用 react-router-dom 时如何避免“功能组件不能被赋予 refs”?的主要内容,如果未能解决你的问题,请参考以下文章

使用 yarn 工作区和 react-router-dom v6 时如何正确继承上下文?

如何配置tomcat 7以在react中使用react-router-dom?

如何使用 react-router-dom v6 中的历史对象重定向到特定页面

如何在 React.js 中使用 react-router-dom 保持 App() 级别状态不重置?

react-router-dom和本地服务本地开发 (nodewebpack)

使用带有输入的 react-router-dom