0

Problem statement: On clicking the react scroll link, the link is not highlighted(I've used spy) and it is not scrolling to the div instead just landing to the page.

Is there any other efficient way to do it? As i'm learning react by doing

Page Context component:

export const PageContext = createContext({
    pageId: 'homepage',
    scrollToPage: () => {}
})

There is a homepage component

const Home = () => {

    const [pageId, setPageId] = useState('homepage');
    const anotherCompRef = React.useRef();
    const profileCompRef = React.useRef();

    const scrollToPage = (event) => {
        let pageId = event.target ? event.target.getAttribute('data-pageId') : null
        if (pageId) {
            setPageId(pageId);
            Scroll.scroller.scrollTo(pageId, {
                duration: 500,
                delay: 100,
                smooth: true,
                spy: true,
                exact: true,
                offset: -80,
            })
        }
    }

    const renderer = () => {
        switch (pageId) {
            case 'profile':
                return <ProfileView profileCompRef={profileCompRef}  />
            default:
                return <AnotherView anotherCompRef={anotherCompRef}/>
        }
    }

    return (
            <>
                <PageContext.Provider value={{pageId, scrollToPage: e => scrollToPage(e)}}>
                    <Layout>
                        {renderer()}
                    </Layout>
                </PageContext.Provider>
            </>
    )
}

Layout component:

const Layout = ( {children} ) => {

    return (
            <>
                <Header/>
                <MainContainer children={children}/>
                <Footer />
            </>
    )
}

export default Layout

Profileview component:

const ProfileView = (props) => {

    return (
            <>
                <ProfileContainer id='profile' ref={props.profileCompRef} >
                    do stuff
                </ProfileContainer>
            </>
    )
}

export default ProfileView

AnotherView component

const AnotherView = (props) => {

    return (
            <>
                <AnotherViewContainer id='anotherView' ref={props.anotherCompRef} >
                    do stuff
                </AnotherViewContainer>
            </>
    )
}

export default AnotherView

Header component:

const Header = () => {

    const pageContext = useContext(PageContext)

    return (
            <>
                <NavbarContainer>
                    <NavbarMenu>
                        <NavItem>
                            <NavLink to='profile' data-pageId='profile' smooth={true} duration={500} spy={true} exact='true' offset={-80} onClick={(e) => pageContext.scrollToPage(e)}>
                                Profile
                            </NavLink>
                        </NavItem>
                        <NavItem>
                            <NavLink to='anotherView' data-pageId='anotherView' smooth={true} duration={500} spy={true} exact='true' offset={-80} onClick={(e) => pageContext.scrollToPage(e)}>
                                Another View
                            </NavLink>
                        </NavItem>
                    </NavbarMenu>
                </NavbarContainer>
            </>
    )
}

export default Header
SparkOn
  • 8,806
  • 4
  • 29
  • 34

1 Answers1

1

I have mainly fixed the below mentioned issues.

  • Enable browser scroll by setting the page height more than the viewport height. Only then scrolling can happen.
  • Not suitable to add a click event to react-scroll Link. So I developed a custom link.

Also did some modifications in updating the pageId also.

Note - Below mentioned only about updated files.

Header.js

import { useContext } from "react";
import PageContext from "./PageContext";

const Header = () => {
  const { pageId, setPageId } = useContext(PageContext);

  const scrollTo = (e) => {
    e.preventDefault();
    setPageId(e.target.dataset.pageid);
  };

  return (
    <>
      <div>
        <div>
          <div>
            <a
              href="#profile"
              data-pageid="profile"
              onClick={scrollTo}
              className={`${pageId === "profile" ? "active" : ""}`}
            >
              Profile
            </a>
          </div>
          <div>
            <a
              href="#anotherview"
              data-pageid="anotherview"
              onClick={scrollTo}
              className={`${pageId === "anotherview" ? "active" : ""}`}
            >
              Another View
            </a>
          </div>
        </div>
      </div>
    </>
  );
};

export default Header;

Home.js

import { useEffect, useRef, useState } from "react";
import { scroller } from "react-scroll";
import AnotherView from "./AnotherView";
import Layout from "./Layout";
import PageContext from "./PageContext";
import ProfileView from "./ProfileView";

const Home = () => {
  const [pageId, setPageId] = useState("homepage");
  const anotherCompRef = useRef();
  const profileCompRef = useRef();

  useEffect(() => {
    if (pageId !== "homepage")
      scroller.scrollTo(pageId, {
        duration: 500,
        delay: 100,
        smooth: true
      });
  }, [pageId]);

  const renderer = () => {
    switch (pageId) {
      case "profile":
        return <ProfileView profileCompRef={profileCompRef} />;
      default:
        return <AnotherView anotherCompRef={anotherCompRef} />;
    }
  };

  return (
    <>
      <PageContext.Provider value={{ pageId, setPageId }}>
        <Layout>{renderer()}</Layout>
      </PageContext.Provider>
    </>
  );
};

export default Home;

Layout.js

import { useContext } from "react";
import Header from "./Header";
import PageContext from "./PageContext";

const Layout = ({ children }) => {
  const { pageId } = useContext(PageContext);

  return (
    <>
      <Header />
      <div id={pageId} children={children} />
    </>
  );
};

export default Layout;

styles.css

#root {
  height: calc(100vh + 100px);
}

a.active {
  color: red;
}

https://codesandbox.io/s/scrolling-with-react-scroll-68043895-bqt10?file=/src/Home.jsx

Let me know if you need further support.

Yushan
  • 1,029
  • 1
  • 9
  • 12
  • Let's assume that the height is always 100vh of both ProfileContainer and AnotherView container. I could have used the anchor tag but the main idea here is to understand why react-scroll does not work and how to fix the react-scroll spy working with this piece of code.. – SparkOn Jun 19 '21 at 13:28
  • @SparkOn, check the highlighted fixes in my answer. You cannot scroll if the page is not scrollable. That's a basic principle. The `Link` is not suitable because you want to add an onClick handler – Yushan Jun 19 '21 at 20:56
  • This did not solve the root cause of the issue for which the question was asked but there is really a good alternative to the problem... – SparkOn Jun 23 '21 at 07:15