【问题标题】:How do I avoid 'Function components cannot be given refs' when using react-router-dom?使用 react-router-dom 时如何避免“功能组件不能被赋予 refs”?
【发布时间】: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}
    />;
}

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

【问题讨论】:

    标签: reactjs react-router material-ui


    【解决方案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-libraryhttps://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 解决了这个问题。
          猜你喜欢
          • 1970-01-01
          • 2020-08-10
          • 2022-01-21
          • 2019-11-03
          • 2023-03-24
          • 2021-09-16
          • 2019-12-16
          • 2020-12-22
          相关资源
          最近更新 更多