Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next/link doesn't work when child is function component #8425

Closed
caribou-code opened this issue Aug 19, 2019 · 9 comments
Closed

next/link doesn't work when child is function component #8425

caribou-code opened this issue Aug 19, 2019 · 9 comments

Comments

@caribou-code
Copy link

Bug report

Describe the bug

When using next/link and passing a function component as the child, it does a full server side render and page refresh on click rather than a client side routing.

To Reproduce

The following link works:

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

const TestThing = () => (
  <Link as="/en/checkout" href="/[locale]/checkout" passHref>
    <a>Checkout</a>
  </Link
);

The following does a SSR load rather than client side on click:

const Button = ({ children }) => (
  <a className="button">
    {children}
  </a>
);

const TestThing = () => (
  <Link as="/en/checkout" href="/[locale]/checkout" passHref>
    <Button>Checkout</Button>
  </Link
);

Additional context

I've seen a new addition to the README in v9.0.4-canary.2:
Note: if passing a functional component as a child of <Link> you will need to wrap it in React.forwardRef

I've tried various methods of adding a ref including forwardRef on my Button component but nothing seems to work. Perhaps I'm doing it wrong. Can someone confirm whether this is a bug with the link component or just provide an example of how this should look with the correct ref setup? I feel like the docs are not clear on this.

@kachkaev
Copy link
Contributor

Guess your button component should simply relay href to <a>:

-const Button = ({ children }) => (
-  <a className="button">
+const Button = ({ children, href }) => (
+  <a className="button" href={href}>
     {children}
   </a>
 );

It might be a good idea to pass title down too.

@ijjk
Copy link
Member

ijjk commented Aug 19, 2019

Hi, the syntax to use React.forwardRef with a function component would be

import React from "react";
import Link from "next/link";

const Button = React.forwardRef(({ children, href, onClick }, ref) => (
  <a
    ref={ref}
    href={href}
    onClick={onClick}
    className="button"
  >
    {children}
  </a>
));

const TestThing = () => (
  <Link href="/" passHref>
    <Button>Checkout</Button>
  </Link>
);

export default TestThing;

For more information on forwardRef see the React docs here. If you are still having trouble with this feel free to reply with additional info

@ijjk ijjk closed this as completed Aug 19, 2019
@caribou-code
Copy link
Author

@ijjk Thank you but I can confirm this is not working. Same problem where it creates the anchor with the correct href but clicking it does a SSR rather than client side route change. Since I am correctly applying the forwardRef and the link correctly does client side routing when using an anchor tag directly instead of a function component child, I can only assume this is a NextJS bug at the moment. Are we able to re-open this issue?

@ijjk
Copy link
Member

ijjk commented Aug 19, 2019

@caribou-code can you provide a link to a reproduction? We have tests covering forwardRef usage with next/link here so it doesn't seem as likely to be related to that. There might be something else not lining up which can be seen easier with a reproduction

@caribou-code
Copy link
Author

@ijjk Ok I've discovered I was missing the onClick prop in my Button component and that's what was breaking it (I realise now you had that in your example above). I just assumed I didn't need it because I'm not using click events or useRouter and I'm only concerned with the as and href values on a next/link. I feel like this definitely needs documenting somewhere.

@Macro80-20
Copy link

Bug report

Describe the bug

When using next/link and passing a function component as the child, it does a full server side render and page refresh on click rather than a client side routing.

To Reproduce

The following link works:

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

const TestThing = () => (
  <Link as="/en/checkout" href="/[locale]/checkout" passHref>
    <a>Checkout</a>
  </Link
);

The following does a SSR load rather than client side on click:

const Button = ({ children }) => (
  <a className="button">
    {children}
  </a>
);

const TestThing = () => (
  <Link as="/en/checkout" href="/[locale]/checkout" passHref>
    <Button>Checkout</Button>
  </Link
);

Additional context

I've seen a new addition to the README in v9.0.4-canary.2:
Note: if passing a functional component as a child of <Link> you will need to wrap it in React.forwardRef

I've tried various methods of adding a ref including forwardRef on my Button component but nothing seems to work. Perhaps I'm doing it wrong. Can someone confirm whether this is a bug with the link component or just provide an example of how this should look with the correct ref setup? I feel like the docs are not clear on this.

For this routing to work without refresh how does your pages look lilke?
e.g. pages -> [locale].js or is it something else

@SassySyntax
Copy link

Guess your button component should simply relay href to <a>:

-const Button = ({ children }) => (
-  <a className="button">
+const Button = ({ children, href }) => (
+  <a className="button" href={href}>
     {children}
   </a>
 );

It might be a good idea to pass title down too.

I was dealing with this issue exactly--and this solved my problem!

Now I'm wondering why Next.js wants navigation links to be written like this?

@jfoxworth
Copy link

This seems like a really big issue.
I have an functional component that is an icon based on the text that is fed in through a prop. Sometimes, it's just an icon. Sometimes, it's a link too. The icon doesn't have an anchor tag to pass the ref to and I shouldn't have to create a separate reusable component just so I can pass a ref from the link.

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants