Next.js: Next 9 - Assigning a ref to the child of <Link> no longer works

Created on 10 Jul 2019  路  3Comments  路  Source: vercel/next.js

Bug report

Describe the bug

In Next 8, the ref attached to an <a> element inside of <Link> was working correctly. With the introduction of intersection observer in Next 9, it looks like this ref is getting overwritten, even with prefetch disabled.

To Reproduce

Here's an example page:

import Link from "next/link";
import { useRef, useEffect } from "react";

const Home = () => {
  const buttonRef = useRef();

  useEffect(() => {
    console.log("buttonRef", buttonRef);
  });

  return (
    <Link href="/">
      <a ref={buttonRef}>click me</a>
    </Link>
  );
};

export default Home;

Steps to reproduce the behavior:

  1. Load the page
  2. Check the console

Expected behavior

buttonRef.current's value in Next 8 is a reference to the <a> tag. In Next 9, it's undefined.

System information

  • Version of Next.js: 9.0.0

Additional context

Not sure if this is an intended breaking change, but would be useful documented if so.

bug needs investigation

Most helpful comment

resolved this with

          <Link route=">
            <AddButton />
          </Link>
 import React from 'react'
 import PropTypes from 'prop-types'
 import clsx from 'clsx'

 import Button from '@material-ui/core/Button'
 import AddIcon from '@material-ui/icons/Add'

-const AddButton = props => {
+const AddButton = (props, ref) => {
   const { classes, className: classNameProp, ...other } = props

   return (
     <Button
       variant="outlined"
       size="small"
       color="default"
       aria-label="Add"
       className={clsx(classes.addButton, classNameProp)}
+      ref={ref}
       {...other}
     >
       <AddIcon />
       Add
     </Button>
   )
 }

-AddButton.propTypes = {
+// fix "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
+const AddButton_ = React.forwardRef(AddButton)
+
+// fix "forwardRef render functions do not support propTypes or defaultProps"
+AddButton_.propTypes = {
   classes:   PropTypes.object.isRequired,
   className: PropTypes.string,
 }

-AddButton.defaultProps = {
+AddButton_.defaultProps = {
   className: undefined,
 }

-export default AddButton
+export default AddButton_

All 3 comments

I'm experiencing this too! Running into it when trying to make a link draggable through react-beautiful-dnd; I have a little wrapper component like this:

const Link = forwardRef(
  ({ children, href, ...rest }, ref) => (
    <NextLink href={href}>
      <a ref={ref} {...rest}>
        {children}
      </a>
    </NextLink>
  )
);

That react-beautiful-dnd is trying to get a reference too. The value of ref seems to be as expected, but react-beautiful-dnd still complains about not being able to find the ref element.

I'm experiencing this too. Any updates on this? I don't know if this is an intended behavior or not, but i didn't find any docs about this :/

resolved this with

          <Link route=">
            <AddButton />
          </Link>
 import React from 'react'
 import PropTypes from 'prop-types'
 import clsx from 'clsx'

 import Button from '@material-ui/core/Button'
 import AddIcon from '@material-ui/icons/Add'

-const AddButton = props => {
+const AddButton = (props, ref) => {
   const { classes, className: classNameProp, ...other } = props

   return (
     <Button
       variant="outlined"
       size="small"
       color="default"
       aria-label="Add"
       className={clsx(classes.addButton, classNameProp)}
+      ref={ref}
       {...other}
     >
       <AddIcon />
       Add
     </Button>
   )
 }

-AddButton.propTypes = {
+// fix "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
+const AddButton_ = React.forwardRef(AddButton)
+
+// fix "forwardRef render functions do not support propTypes or defaultProps"
+AddButton_.propTypes = {
   classes:   PropTypes.object.isRequired,
   className: PropTypes.string,
 }

-AddButton.defaultProps = {
+AddButton_.defaultProps = {
   className: undefined,
 }

-export default AddButton
+export default AddButton_
Was this page helpful?
0 / 5 - 0 ratings