fisshy / react-scroll

React scroll component
https://github.com/fisshy/react-scroll/blob/master/README.md
MIT License
4.36k stars 437 forks source link

react-scroll is not working with nextjs #476

Closed shivika24 closed 2 years ago

shivika24 commented 3 years ago

react-scroll is not working with nextjs.

i migrated react codebase to nextjs, but react-scroll is not working with nextjs.

fisshy commented 3 years ago

Ok, I think we had an issue like this long time back, it got solved I believe, but new code might have introduced the unsupport.

What type of errors do you get?

And also feel free to make a PR supporting it!

shivika24 commented 3 years ago

I don't get any error, but the scrolling is not working.

roydenrego commented 3 years ago

@shivika24 I'm using react-scroll with Next.js 11 and it's mostly working fine for me. The only issue I'm facing is with smooth scroll when using bootstrap 5 #475.

shivika24 commented 3 years ago

I am using react-scroll like this

    <Link
      activeClass="active"
      to="about"
      offset={-110}
      spy={true}
      smooth={true}
    > Home </Link>

and have a div with id "about" but this is not working.

keXXpert commented 3 years ago

@shivika24 maybe you have more than one '#about' tag/element? Try to give it a more distinctive name. And maybe you need to add 'duration' to your Link tag.

Btw, I have react-scroll working with Next.js 11.

hbole commented 3 years ago

Any luck on this @shivika24 ??

@keXXpert have implemented the react-scroll the same way. Also re-checked for duplicate tags/elements. But there aren't any duplicates.

Here is my implementation

<Link
  activeClass="nav-active"
  className="nav"
  to={"homepage"}
  spy={true}
  smooth={true}
  duration={500}
  offset={-50}
>
    HOME
</Link>
<Link
  activeClass="nav-active"
  className="nav"
  to={"highlightspage"}
  spy={true}
  smooth={true}
  duration={500}
  offset={-50}
>
    HIGHLIGHTS
</Link>

In the beginning, Home is correctly highlighted but that remains constant and also when clicked on any other Link tags the page doesn't scroll and even on manual scrolling the active Link doesn't change. Please help

ZahirHashemiNasab commented 3 years ago

it works for me very good

I used it for a box to horizontally scroll backward and forward on a div on Click in the following way: and it works very nice.

import * as Scroll from 'react-scroll';

  let scroll = Scroll.animateScroll;

  const scrollForward = (container: string) => {
    scroll.scrollMore(100, {
      horizontal: 'true',
      containerId: container,
    });
  };
  const scrollBackward = (container: string) => {
    scroll.scrollMore(-100, {
      horizontal: 'true',
      containerId: container,
    });
  };
//////
              <div
                className={styles2.swiperNext}
                onClick={() => scrollForward('proposalDaily')}>
                <img src='./next.png' />
              </div>
              <div
                className={styles2.swiperBack}
                onClick={() => scrollBackward('proposalDaily')}>
                <img src='./back.png' />
              </div>
///////
          <div className={styles2.promoBody} id='proposalDaily'>
            <div style={{ display: 'flex', padding: '10px' }}>
              {food2.map((e) => (
                <FoodCard element={e} type={1} key={e.id} id={`card_${e.id}`} />
              ))}
            </div>
          </div>
nikitagcode commented 3 years ago

When I use the button component in the next js an error pops up in the document js file : "error: input is a void element tag and must neither have children nor use dangerouslySetInnerHTML".

fisshy commented 3 years ago

@nikitaskittcode

Can you try creating your own Button and omit the { this.props.children }

import React from 'react';
import ScrollLink from '../mixins/scroll-link';

class ButtonElement extends React.Component{
  render() {
    return (
      <input {...this.props}></input>
    );
  }
};

export default ScrollLink(ButtonElement);
nikitagcode commented 3 years ago

@nikitaskittcode

Can you try creating your own Button and omit the { this.props.children }

import React from 'react';
import ScrollLink from '../mixins/scroll-link';

class ButtonElement extends React.Component{
  render() {
    return (
      <input {...this.props}></input>
    );
  }
};

export default ScrollLink(ButtonElement);

No, its not working.

nikitagcode commented 3 years ago

Link component has no such problems with next js.

nikitagcode commented 3 years ago

I think that problem in <"input/">

mogw commented 3 years ago

I copied the basic react-scroll sample into default empty pages/index.js in Next.js.

Scrolling is not working without any console error.

vmaark commented 3 years ago

same problem in next.js

Csutkas commented 3 years ago

same, any workaround?

fisshy commented 3 years ago

I just created a new Nextjs app and only installed react-scroll, this is the code.

Everything works fine for me, or am I missing somthing?

import Head from 'next/head'
import { Element, Link } from 'react-scroll'

export default function Home() {
  return (
    <div className="container">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1 className="title">
          Welcome to <a href="https://nextjs.org">Next.js!</a>

        </h1>

        <p className="description">
          Get started by editing <code>pages/index.js</code>
        </p>

        <div className="grid">
          <Link to="section1" smooth={true} className="card">
            <h3>Section 1</h3>
          </Link>

          <Link to="section2" smooth={true} className="card">
            <h3>Section 2</h3>
          </Link>

          <Link to="section3" smooth={true} className="card">
            <h3>Section 3</h3>
          </Link>
        </div>
      </main>

      <Element className="element" name="section1" >
        Section one
      </Element>
      <Element className="element" name="section2" >
        Section two
      </Element>
      <Element className="element" name="section3" >
        Section three
      </Element>

      <style jsx>{`
        .container {
          min-height: 100vh;
          padding: 0 0.5rem;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        main {
          padding: 5rem 0;
          flex: 1;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        footer {
          width: 100%;
          height: 100px;
          border-top: 1px solid #eaeaea;
          display: flex;
          justify-content: center;
          align-items: center;
        }

        footer img {
          margin-left: 0.5rem;
        }

        footer a {
          display: flex;
          justify-content: center;
          align-items: center;
        }

        a {
          color: inherit;
          text-decoration: none;
        }

        .title a {
          color: #0070f3;
          text-decoration: none;
        }

        .title a:hover,
        .title a:focus,
        .title a:active {
          text-decoration: underline;
        }

        .title {
          margin: 0;
          line-height: 1.15;
          font-size: 4rem;
        }

        .title,
        .description {
          text-align: center;
        }

        .description {
          line-height: 1.5;
          font-size: 1.5rem;
        }

        code {
          background: #fafafa;
          border-radius: 5px;
          padding: 0.75rem;
          font-size: 1.1rem;
          font-family: Menlo, Monaco, Lucida Console, Liberation Mono,
            DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
        }

        .grid {
          display: flex;
          align-items: center;
          justify-content: center;
          flex-wrap: wrap;

          max-width: 800px;
          margin-top: 3rem;
        }

        .card {
          margin: 1rem;
          flex-basis: 45%;
          padding: 1.5rem;
          text-align: left;
          color: inherit;
          text-decoration: none;
          border: 1px solid #eaeaea;
          border-radius: 10px;
          transition: color 0.15s ease, border-color 0.15s ease;
        }

        .card:hover,
        .card:focus,
        .card:active {
          color: #0070f3;
          border-color: #0070f3;
        }

        .card h3 {
          margin: 0 0 1rem 0;
          font-size: 1.5rem;
        }

        .card p {
          margin: 0;
          font-size: 1.25rem;
          line-height: 1.5;
        }

        .logo {
          height: 1em;
        }

        @media (max-width: 600px) {
          .grid {
            width: 100%;
            flex-direction: column;
          }
        }
      `}</style>

      <style jsx global>{`
        html,
        body {
          padding: 0;
          margin: 0;
          font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
            Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
            sans-serif;
        }

        * {
          box-sizing: border-box;
        }

        .element {
          height:100vh;
          width:100%;
        }
      `}</style>
    </div>
  )
}
Csutkas commented 3 years ago

Thanks for the example. I double checked my project and now it works fine. Sorry for the misleading, it was my fault.

santyas commented 2 years ago

Works fine on Next.js 12. I had to add @ts-ignore before import line (I'm using typescript).

I want to know what happen if I have Links or Button outside the page, in an external component but my Element to aim the scroll is inside index.tsx

santyas commented 2 years ago

Works fine on Next.js 12. I had to add @ts-ignore before import line (I'm using typescript).

I want to know what happen if I have Links or Button outside the page, in an external component but my Element to aim the scroll is inside index.tsx

Reducer / Context is not needed. Works perfectly from another component: caminofilms.tv

douglasjunior commented 2 years ago

Anyone had problem with browser back button? https://github.com/vercel/next.js/issues/7091

Here, the react-scroll breaks NextJS navigation when the user click in the browser back button.

Dathix commented 2 years ago

I am facing the same problem with the back button when using react-scroll with NextJS.

douglasjunior commented 2 years ago

Our solution is to prevent that react-scroll changes the browser URL, removing the hashSpy and creating a custom Link component with <a href={} />:

import React, { useCallback } from 'react';

import { scroller, ScrollLink as WrapLink } from 'react-scroll';

import useClassNames from '~/hooks/use-classnames';

import styles from './Link.module.scss';

const WrappedLink = WrapLink(({
    children,
    redirectTo,
    scrollOffset,
    ...otherProps
}) => {

    const handleLinkClick = useCallback(() => {
        scroller.scrollTo(redirectTo, {
            offset: scrollOffset,
            smooth: true,
        });
    }, [scrollOffset, redirectTo]);

    return (
        <a
            {...otherProps}
            href={`#${redirectTo}`}
            onClick={handleLinkClick}
        >
            {children}
        </a>
    );
});

const ScrollLink = ({
    children,
    className,
    ...otherProps
}) => {
    const linkClasses = useClassNames([
        className,
        styles.link,
    ]);

    return (
        <WrappedLink
            spy
            smooth
            isDynamic
            className={linkClasses}
            redirectTo={otherProps.to}
            activeClass={styles.linkActive}
            scrollOffset={otherProps.offset}
            {...otherProps}
        >
            {children}
        </WrappedLink>
    );
};

export default ScrollLink;
Dathix commented 2 years ago

@douglasjunior thanks for your suggestion but the usage of the hashSpy was the main reason for choosing react-scroll. Shouldn't there be a solution for this?

douglasjunior commented 2 years ago

@douglasjunior thanks for your suggestion but the usage of the hashSpy was the main reason for choosing react-scroll. Shouldn't there be a solution for this?

For sure, our solution is a workaround, it works for us as we don't need spy, we just need autoscroll.

Dathix commented 2 years ago

@fisshy do you think there is something we can do here?

fisshy commented 2 years ago

@Dathix I tried it out with react-scroll, and it worked for me.

Could you provide a codesnippet that doesn't work in nextjs and I'll look into it.

douglasjunior commented 2 years ago

@fisshy our problem is simple to reproduce:

Then:

  1. Open the page 1, scroll to the bottom using the mouse scroll to make the URL hash update with spy.
  2. Click in footer next link to navigate to the page 2.
  3. In page 2, click on the browser Back Button to go back to the page 1.

btw, I think that this is a Next limitation (https://github.com/vercel/next.js/issues/7091), since the react-scroll works fine with react-router and with gatsby.

fisshy commented 2 years ago

@douglasjunior It seems to work fine for me. What is suppose to happen?

douglasjunior commented 2 years ago

Sorry, I missed an important step. After navigate to page 2, refresh the page (F5), then press back button to return to page 1.

fisshy commented 2 years ago

@douglasjunior What is supposed to happen? It works fine for me. I've added 3 sections and a button at the bottom that takes me to page 2. And page two looks identical to page 1.

  1. Scroll to to bottom. Section3 gets hash-spied /#section3
  2. Navigate to page 2, hash and page has now changed
  3. F5/Reload page
  4. Press back button
  5. Navigates to page one with /#section3 as hash.

This is the expected behaviour I guess? I'm using edge.

fisshy commented 2 years ago

Page one

import Head from 'next/head'
import { Element, Link } from 'react-scroll'

export default function Home() {
  return (
    <div className="container">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1 className="title">
          Welcome to <a href="https://nextjs.org">Next.js!</a>

        </h1>

        <p className="description">
          Get started by editing <code>pages/index.js</code>
        </p>

        <div className="grid">
          <Link to="section1" hashSpy={true} smooth={true} className="card">
            <h3>Section 1</h3>
          </Link>

          <Link to="section2" hashSpy={true} smooth={true} className="card">
            <h3>Section 2</h3>
          </Link>

          <Link to="section3" hashSpy={true} smooth={true} className="card">
            <h3>Section 3</h3>
          </Link>
        </div>
      </main>

      <Element className="element" name="section1" >
        Section one
      </Element>
      <Element className="element" name="section2" >
        Section two
      </Element>
      <Element className="element" name="section3" >
        Section three
      </Element>

      <div>
        <a href="/page2">Page 2</a>
      </div>

      <style jsx>{`
        .container {
          min-height: 100vh;
          padding: 0 0.5rem;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        main {
          padding: 5rem 0;
          flex: 1;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        footer {
          width: 100%;
          height: 100px;
          border-top: 1px solid #eaeaea;
          display: flex;
          justify-content: center;
          align-items: center;
        }

        footer img {
          margin-left: 0.5rem;
        }

        footer a {
          display: flex;
          justify-content: center;
          align-items: center;
        }

        a {
          color: inherit;
          text-decoration: none;
        }

        .title a {
          color: #0070f3;
          text-decoration: none;
        }

        .title a:hover,
        .title a:focus,
        .title a:active {
          text-decoration: underline;
        }

        .title {
          margin: 0;
          line-height: 1.15;
          font-size: 4rem;
        }

        .title,
        .description {
          text-align: center;
        }

        .description {
          line-height: 1.5;
          font-size: 1.5rem;
        }

        code {
          background: #fafafa;
          border-radius: 5px;
          padding: 0.75rem;
          font-size: 1.1rem;
          font-family: Menlo, Monaco, Lucida Console, Liberation Mono,
            DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
        }

        .grid {
          display: flex;
          align-items: center;
          justify-content: center;
          flex-wrap: wrap;

          max-width: 800px;
          margin-top: 3rem;
        }

        .card {
          margin: 1rem;
          flex-basis: 45%;
          padding: 1.5rem;
          text-align: left;
          color: inherit;
          text-decoration: none;
          border: 1px solid #eaeaea;
          border-radius: 10px;
          transition: color 0.15s ease, border-color 0.15s ease;
        }

        .card:hover,
        .card:focus,
        .card:active {
          color: #0070f3;
          border-color: #0070f3;
        }

        .card h3 {
          margin: 0 0 1rem 0;
          font-size: 1.5rem;
        }

        .card p {
          margin: 0;
          font-size: 1.25rem;
          line-height: 1.5;
        }

        .logo {
          height: 1em;
        }

        @media (max-width: 600px) {
          .grid {
            width: 100%;
            flex-direction: column;
          }
        }
      `}</style>

      <style jsx global>{`
        html,
        body {
          padding: 0;
          margin: 0;
          font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
            Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
            sans-serif;
        }

        * {
          box-sizing: border-box;
        }

        .element {
          height:100vh;
          width:100%;
        }
      `}</style>
    </div>
  )
}

Page two


import Head from 'next/head'
import { Element, Link } from 'react-scroll'

export default function Home() {
  return (
    <div className="container">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1 className="title">
          Welcome to page two!
        </h1>

        <p className="description">
          Get started by editing <code>pages/index.js</code>
        </p>

        <div className="grid">
          <Link to="section1" hashSpy={true} smooth={true} className="card">
            <h3>Section 1</h3>
          </Link>

          <Link to="section2" hashSpy={true} smooth={true} className="card">
            <h3>Section 2</h3>
          </Link>

          <Link to="section3" hashSpy={true} smooth={true} className="card">
            <h3>Section 3</h3>
          </Link>
        </div>
      </main>

      <Element className="element" name="section1" >
        Section one
      </Element>
      <Element className="element" name="section2" >
        Section two
      </Element>
      <Element className="element" name="section3" >
        Section three
      </Element>

      <style jsx>{`
        .container {
          min-height: 100vh;
          padding: 0 0.5rem;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        main {
          padding: 5rem 0;
          flex: 1;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }

        footer {
          width: 100%;
          height: 100px;
          border-top: 1px solid #eaeaea;
          display: flex;
          justify-content: center;
          align-items: center;
        }

        footer img {
          margin-left: 0.5rem;
        }

        footer a {
          display: flex;
          justify-content: center;
          align-items: center;
        }

        a {
          color: inherit;
          text-decoration: none;
        }

        .title a {
          color: #0070f3;
          text-decoration: none;
        }

        .title a:hover,
        .title a:focus,
        .title a:active {
          text-decoration: underline;
        }

        .title {
          margin: 0;
          line-height: 1.15;
          font-size: 4rem;
        }

        .title,
        .description {
          text-align: center;
        }

        .description {
          line-height: 1.5;
          font-size: 1.5rem;
        }

        code {
          background: #fafafa;
          border-radius: 5px;
          padding: 0.75rem;
          font-size: 1.1rem;
          font-family: Menlo, Monaco, Lucida Console, Liberation Mono,
            DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
        }

        .grid {
          display: flex;
          align-items: center;
          justify-content: center;
          flex-wrap: wrap;

          max-width: 800px;
          margin-top: 3rem;
        }

        .card {
          margin: 1rem;
          flex-basis: 45%;
          padding: 1.5rem;
          text-align: left;
          color: inherit;
          text-decoration: none;
          border: 1px solid #eaeaea;
          border-radius: 10px;
          transition: color 0.15s ease, border-color 0.15s ease;
        }

        .card:hover,
        .card:focus,
        .card:active {
          color: #0070f3;
          border-color: #0070f3;
        }

        .card h3 {
          margin: 0 0 1rem 0;
          font-size: 1.5rem;
        }

        .card p {
          margin: 0;
          font-size: 1.25rem;
          line-height: 1.5;
        }

        .logo {
          height: 1em;
        }

        @media (max-width: 600px) {
          .grid {
            width: 100%;
            flex-direction: column;
          }
        }
      `}</style>

      <style jsx global>{`
        html,
        body {
          padding: 0;
          margin: 0;
          font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
            Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
            sans-serif;
        }

        * {
          box-sizing: border-box;
        }

        .element {
          height:100vh;
          width:100%;
        }
      `}</style>
    </div>
  )
}
Dathix commented 2 years ago

@fisshy I tried it with different projects and the problem always occurs. As soon as I scroll a page that was opened by a next/link and the hash in the URL changes by the usage of hashSpy I cannot use the back button of the browser to open the previous page. The router history inside next seems to become broken after the first URL change of the hashSpy.

All tested projects are still using next.js v10 and react v16. Maybe this is where the issue comes from...

douglasjunior commented 2 years ago

@fisshy you have used a to navigate from page 1 to 2. You need to use next/link.

https://user-images.githubusercontent.com/1512341/155973440-0adeee7c-948a-4496-b92e-a9ca70711b50.mov

Versions:

    "next": "12.1.0",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-scroll": "1.8.5"
Page 1: ```jsx import Head from 'next/head' import NextLink from 'next/link'; import { Element, Link } from 'react-scroll' export default function Home() { return (
Home

Welcome to Next.js!

Get started by editing pages/index.js

Section 1

Section 2

Section 3

Section one Section two Section three
Page 2
) } ```
Page 2: ```jsx import Head from 'next/head' export default function Home() { return (
Page 2

Welcome to page two!

) } ```
fisshy commented 2 years ago

Aha I see, will check it out

fisshy commented 2 years ago

I've figured out the issue atleast, but not the solution.

If I set the hash with window.location.hash = "#section1" and navigate to page2 with NextLink, then navigating back to page1/#section1 is not a problem.

But If I set it with history push/replace then nextjs doesn't seem to understand that.

douglasjunior commented 2 years ago

Have you checked the discuss about this problem here https://github.com/vercel/next.js/issues/7091 ?

Maybe this can help too https://github.com/vercel/next.js/issues/33233#issuecomment-1052349396

fisshy commented 2 years ago

@douglasjunior good catch, providing state to history actually solved the issue. But I must make sure it doesn't cause any other, but I can't think of any atm.

fisshy commented 2 years ago

@douglasjunior I've pushed the new changes, could you try it out with npm link?

You've to npm link the build of react-scroll, and not the root.

npm run build cd build\npm npm link

https://github.com/fisshy/react-scroll/commit/7ed6933627b1a39515730c1e55ca26f7066ec615

douglasjunior commented 2 years ago

@fisshy It looks like it was resolved, I had to delete the ".cache" from next to apply the fix, but now the "back button" works correctly.

Tested on Firefox, Chrome, Safari and Opera.

https://user-images.githubusercontent.com/1512341/156353538-8c58f5e9-78ba-4b22-bb40-bedc160737fa.mov

fisshy commented 2 years ago

@douglasjunior Great to hear! I'll publish a new version sometime today :)

Dathix commented 2 years ago

@fisshy Awesome! Everything works fine now! Thanks for your endurance on this one :) @douglasjunior Thanks for your curiosity as well ;)

fisshy commented 2 years ago

@Dathix Glad to hear that! I've now publish v1.8.6.

L53c commented 2 years ago

I spent several hours until I realised that my css was stopping react-scroll from working correctly // overflow-y: scroll; ::-webkit-scrollbar { display: none; }

Screenshot 2022-06-05 at 08 11 51
PastelBlue4 commented 2 years ago

I spent several hours until I realised that my css was stopping react-scroll from working correctly // overflow-y: scroll; ::-webkit-scrollbar { display: none; } Screenshot 2022-06-05 at 08 11 51

you are my hero

robitaille1 commented 2 years ago

I spent several hours until I realised that my css was stopping react-scroll from working correctly // overflow-y: scroll; ::-webkit-scrollbar { display: none; } Screenshot 2022-06-05 at 08 11 51

Yup, this was the fix for me too

sollidy commented 2 years ago

just delete css property in body: scroll-behavior: smooth

mhassanpur commented 1 year ago

I spent several hours until I realised that my css was stopping react-scroll from working correctly // overflow-y: scroll; ::-webkit-scrollbar { display: none; } Screenshot 2022-06-05 at 08 11 51

In my case the culprit was a global overflow-x: hidden; rule.

santyas commented 1 year ago

@fisshy @douglasjunior what about if you have a shared nav layout with links (next/link component) on every page on a nextjs project that points to differents pages but some of those links needs to scroll (with react-scroll) to X divs inside pages after change the url?

douglasjunior commented 1 year ago

@santyas you need to handle this yourself, page per page.

We have a similar nav in some projects too, so we apply the nav page by page passing the URL or scroll ID when necessary.

santyas commented 1 year ago

@santyas you need to handle this yourself, page per page.

We have a similar nav in some projects too, so we apply the nav page by page passing the URL or scroll ID when necessary.

Great, I've added an scrollTo within useEffect to do scroll to the Element name which is passed with hashtag by the url. And the navbar has next/link components with the href value "/#name" and the scroll property value "false".