Next.js组件遇ForwardRef警告,React.forwardRef无效如何解决?
问题:Next.js AppBarContent组件的ref警告问题
组件代码
const AppBarContent = (props: Props) => { // ** Props const { horizontalAppBarContent: userHorizontalAppBarContent, horizontalAppBarBranding: userHorizontalAppBarBranding, } = props // ** Hooks const theme = useTheme() return ( <div style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', }} > {userHorizontalAppBarBranding ? ( userHorizontalAppBarBranding(props) ) : ( <Link href="/"> <Image src={'/images/logo.svg'} width={48} height={48} /> </Link> )}
警告信息
next-dev.js?3515:25 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
ForwardRef.
尝试操作与疑问
- 按提示用
const AppBarContent = React.forwardRef((props: Props, ref) => {})包裹组件后,警告仍存在; - 在
<Link>和<Image>之间添加<a>标签后,警告消失,但认为这是不符合Next.js文档的临时方案; - 想了解正确解决方法,以及为何React.forwardRef无效。
调用代码片段
return ( <HorizontalLayoutWrapper className="layout-wrapper"> {/* Navbar (or AppBar) and Navigation Menu Wrapper */} <AppBar color="default" elevation={skin === 'bordered' ? 0 : 3} className="layout-navbar-and-nav-container" position={appBar === 'fixed' ? 'sticky' : 'static'} > {/* Navbar / AppBar */} <div className="layout-navbar"> <div className="navbar-content-container"> <AppBarContent
解决方案
为什么React.forwardRef无效?
警告的根源不在AppBarContent组件本身,而是Next.js的<Link>组件会尝试给直接子组件传递ref,但Next.js的<Image>是函数式组件,默认无法接收ref。你给AppBarContent添加forwardRef,但问题出在组件内部的<Link>与<Image>的组合逻辑上,所以无法解决警告。
正确解决方法
以下两种方式均符合Next.js官方规范:
方式1:给Link添加passHref,并让Image能接收ref
Next.js的<Link>默认不会将href传递给非原生<a>标签的子组件,需通过passHref开启该行为;同时要确保子组件能接收ref,可通过React.forwardRef包装<Image>:
// 先包装Image,使其能接收ref const ForwardedImage = React.forwardRef((props, ref) => ( <Image ref={ref} {...props} /> )); // 在AppBarContent中使用 <Link href="/" passHref> <ForwardedImage src="/images/logo.svg" width={48} height={48} /> </Link>
如果不需要Next.js <Image>的优化特性,也可以直接使用原生<img>标签:
<Link href="/" passHref> <img src="/images/logo.svg" width={48} height={48} /> </Link>
方式2:Link包裹原生a标签(合规方案)
你之前添加<a>标签的思路是正确的,只要给<Link>加上passHref,这种方式完全符合Next.js文档规范,并非临时方案:
<Link href="/" passHref> <a> <Image src="/images/logo.svg" width={48} height={48} /> </a> </Link>
原生<a>标签可以直接接收<Link>传递的ref,因此不会触发警告。
内容的提问来源于stack exchange,提问作者János
相关产品推荐
相关产品推荐

