Next.js: 下一步9-使用功能组件作为<link/>引起引用警告

创建于 2019-07-12  ·  32评论  ·  资料来源: vercel/next.js

错误报告

描述错误

将功能组件用作<Link/>的子代会导致:

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

仅在从v8 => v9升级后才发生这种情况。

重现

复制回购: https :

预期行为

<Link/>应该与功能组件一起使用/不显示警告。

系统信息

  • Next.js版本:9.0.1

最有用的评论

手动包装Link使用的所有功能组件? 难道不应该有一个更简单,重复性更小的解决方案吗? 至少像<Link href="/" forwardRef>...</Link>

所有32条评论

同样在这里。 如果使用这样的自定义组件,则会出错:

        <Link href="/href">
          <Button
            type="custom"
            color="#FCFCFC"
          >
             buttonText
          </Button>
        </Link>

仅在将组件用作子组件时才会发生这种情况。 这些不发出警告,例如:

        <Link href="/href">
          <button
            type="custom"
            color="#FCFCFC"
          >
            buttonText
          </button>
        </Link>

        <Link href="/href">
          <a>
            <Button
              type="custom"
              color="#FCFCFC"
            >
              buttonText
            </Button>
          </a>
        </Link>

有没有办法解决这个错误? 当我们确实希望利用某些功能(例如打字稿支持)时,我们将无法使用9。 只是注意到它升至9.0.3:/

您可以尝试暂时将其静音,例如:

// TODO: Muting error, fix as soon as zeit/next.js/issues/7915 resolved
const originalError = console.error;

console.error = (...args) => {
  if (/Warning.*Function components cannot be given refs/.test(args[0])) {
    return;
  }
  originalError.call(console, ...args);
};

我在这里有同样的问题。

如果您使用<Link/>包装您的自定义组件,则可以像这样转发ref

const CustomComponent = React.forwardRef(function CustomComponent(props, ref) {
  return (
    <div/>
  );
});
<Link href={"/"}>
  <CustomComponent/>
</Link>

警告消失。

我已更新为9.0.4-canary.2但在控制台上仍然收到警告。 我想念什么吗?

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

Check the render method of `Link`.

@ th0th您应该将组件包装在React.forwardRef 。 像这个:

import React from 'react'
import Link from 'next/link'

const CustomComponent = React.forwardRef((props, ref) => (
  <a ref={ref} {...props}>
    Click
  </a>
))

export default () => (
  <Link href='/' passHref>
    <CustomComponent/>
  </Link>
)

手动包装Link使用的所有功能组件? 难道不应该有一个更简单,重复性更小的解决方案吗? 至少像<Link href="/" forwardRef>...</Link>

同意@nickluger,这似乎违反直觉。

是否所有其他库都应以相同方式实现forwardRef属性? 或者,也许是有反应的创建者认为开发人员将使用React.forwardRef函数而不是实现forwardRef属性?

是的,同意@nickluger ,对Link所有组件手动执行此操作很麻烦

我们应该重新打开并重命名此问题(@ijjk),还是有人已经打开了一个新的问题?

同样在这里。 如果使用这样的自定义组件,则会出错:

        <Link href="/href">
          <Button
            type="custom"
            color="#FCFCFC"
          >
             buttonText
          </Button>
        </Link>

仅在将组件用作子组件时才会发生这种情况。 这些不发出警告,例如:

        <Link href="/href">
          <button
            type="custom"
            color="#FCFCFC"
          >
            buttonText
          </button>
        </Link>

        <Link href="/href">
          <a>
            <Button
              type="custom"
              color="#FCFCFC"
            >
              buttonText
            </Button>
          </a>
        </Link>

这很可能会引发控制台错误:

Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.

我只是在升级Next JS时遇到了这个问题。 有没有解决的办法?

我不确定我是否了解如何使用forwardRef和包装我的组件。 我的button.js文件当前导出以下内容...。

const Button = (props) => {
    return (<stuff />)
}

export default React.memo(Button)

见上文,我在这里打开了后续文件: https :

我只是在升级Next JS时遇到了这个问题。 有没有解决的办法?

我不确定我是否了解如何使用forwardRef和包装我的组件。 我的button.js文件当前导出以下内容...。

const Button = (props) => {
    return (<stuff />)
}

export default React.memo(Button)

在这种情况下,您应该能够

import {forwardRef} from 'react';
const Button = forwardRef(props, ref) => {
    return (<stuff ref={ref} />)
}

对于forwardRef部分。 这些文档还提到了https://nextjs.org/docs#forcing -the-link-to-expose-href-to-its-child,尽管我没有尝试过。 我发现这样做

            <Link
              href={href}
            >
              <a>
                {text}
              </a>
            </Link>

有效(尽管看起来很奇怪。)

在9.0.2中遇到此问题

使用<a></a>可能有效,但在使用a11y和类似方法时会触发其他错误,例如“必须具有href”等。

编辑:花了1500万美元试图弄清楚这一点,这很无聊,很浪费时间,尽管有警告,但似乎仍能正常工作。

就个人而言, https: //github.com/zeit/next.js/issues/7915#issuecomment -511792629容易得多。

使用React片段作为轴承包装的解决方案呢?

import React, { Fragment, useRef } from 'react';
import { MyFunctionalComponent } from './my-functional-component';

const App = props => {
  const myRef = useRef();

  return ( 
    <Link href={href}>
      <Fragment>
          <MyFunctionalComponent ref={myRef} />
      </Fragment>
    </Link>
  );
}

其中<MyFunctionalComponent>转发参考:

import React, { forwardRef } from 'react';

const MyFunctionalComponent = forwardRef(props, ref) => (
  <div ref={ref} />
);

这不会在输出( <div /> )中添加任何其他HTML包装器,并且不会触发任何相关错误。

@ hill84有趣,但是在您的示例中myRef来自哪里?

@Vadorequest我已在先前的评论中添加了更多详细信息。

遵循@ hill84的建议是一个不错的解决方法:
```
const ButtonLink:FC=({{children,href,... props})=>(
<

遵循@ hill84的建议是一个不错的解决方法:

const ButtonLink: FC<ButtonLinkProps> = ({ children, href, ...props }) => (
  <Link href={href}>
    <><Button link {...props}>{children}</Button></>
  </Link>
);

我使用<><Component/></>但链接无法操作。 我必须使用<div></div>代替。

我建议一种解决方案,其中函数返回带有props而不是component的对象:

const propsUserBtn = user => ({
    className: "h-10 w-10 font-black rounded-full bg-orange-200 text-teal-700",
    title: user.first_name + ' ' + user.last_name,
    children: (user.first_name.charAt(0) + user.last_name.charAt(0)).toUpperCase()
})
<Link href='/profile'>
    <button { ...propsUserBtn(user) } />   
</Link>

经检查,可以正常工作!

为什么甚至需要这个裁判? 难道是保证的正确位置href在基础包组件时, passHref在使用<Link />

或者,如果您需要在组件中指定href的位置,则至少可以选择启用它。 <Link href="/" passHref useRef />

我认为不必创建另一个模块来将ref转发到自定义组件是一个很好的解决方案,并且它也很重复。

我用来处理此问题的方式是通过将自定义组件包装为div元素(如@ namlq93所建议的

同样在这里。 如果使用这样的自定义组件,则会出错:

        <Link href="/href">
          <Button
            type="custom"
            color="#FCFCFC"
          >
             buttonText
          </Button>
        </Link>

仅在将组件用作子组件时才会发生这种情况。 这些不发出警告,例如:

        <Link href="/href">
          <button
            type="custom"
            color="#FCFCFC"
          >
            buttonText
          </button>
        </Link>

        <Link href="/href">
          <a>
            <Button
              type="custom"
              color="#FCFCFC"
            >
              buttonText
            </Button>
          </a>
        </Link>

可行,谢谢队友!

遇到类似的问题

还在那儿

https://nextjs.org/docs/api-reference/next/link#if -the-child-is-a-function-component

这真是难过;这真是伤心。

前几天,我在观看NextJS会议时在想“哇,未来就是未来”。 我真的很喜欢Next和Vercel生态系统,我想坦白地说可以成为Next的拥护者。 但是,像这样的问题由于无法解决而无法解决。 在这里的所有问题中,我已经多次看到这种模式,特别是在路由器方面。

从用户方面有3种解决方案,它们都不是出色的DX。

  1. 推荐的方法React.forwardRef。 将组件包装在React.forwardRef 。 这可能是非常重复的
  2. 将功能组件包装在divspana等标签中。
  3. 代替Link,引入useRouter并使用router.push

无论您使用哪种解决方案,它们都很奇怪,需要链接到此问题或文档的注释来向同事/贡献者解释为什么需要这种方法来防止意外删除/清除。

我认为这个问题应该重新讨论。

此页面是否有帮助?
0 / 5 - 0 等级