How to achieve Scrollspy with hash routing using react

I am working with react (Hooks), and I have done a lot of things, but here I have been stuck on one place from few days.

I want to create a scrollspy using react that too with routing, where when on scroll new menu active I want to change the route

[Please refer this link][1] This is what I am trying to achieve, here they are using Hash routing.

What I am doing

  1. I have one sidebar, where I have some Menus.
  2. I am looping data and showing the sidebar, which is working fine.

What I am trying to achieve

  1. For each menu I have some data, I want to show that
  2. So when I scroll and the first menu text ends I want to active the next menu, but also with change of rout
  3. Like have some routes which are — /home , /profile , /status , /info.
  4. So when I **scrollspy **changes the menu I want to change the route also as I have data from Api.
  5. I am not able to show the data In the particular rout, like when I click on Profile I want to show that data in that page, but Not bale to pass that data.

Doing it with simple on click of routing is fine and I am able to achieve it easily, but here I want to achieve something else and facing hard time to do it.

JSON data

    [
    {
      menu: "HOME",
      path: "home",
      data:
        "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
    },
    {
      menu: "PROFILE",
      path: "profile",
      data:
        "The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from 'de Finibus Bonorum et Malorum' by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham."
    },
    {
      menu: "STATUS",
      path: "status",
      data:
        "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English."
    },
    {
      menu: "INFO",
      path: "info",
      data:
        "Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). q"
    }
  ]

In the above data I have data which I want to show show in each respective rout, on scroll or on click.

On click of I have able to change rout and rendering the clicked page.

My code

Below is my Menu bar .js file

<div className="menuBar">
  <Nav className="mr-auto ml-1">
    {data.map((li, ind) => (
      <li className="nav-item" key={li.path}>
        <NavLink
          className="nav-link"
          activeClassName="active"
          to={`${li.path}`}
          onClick={() => OnclickSidebar(li.menu, li.path)}
        >
          {li.menu}
        </NavLink>
      </li>
    ))}
  </Nav>
</div>

route.js file

 <Switch>
    <Route exact path="/" component={Home} />
    <Route exact path="/home" component={Home} />
    <Route path="/profile" component={Profile} />
    <Route path="/status" component={Status} />
    <Route path="/info" component={Info} />
    <Route path="/*" component={() => "Page not found"} />
  </Switch>

Above is What I have achieved till now, Now I am not getting any idea to move forward, so seeking for some idea here.

PS : please refer [This is what I exactly i want][1], here hash routing has been used.

Edit / Update

I have data like above, and I have shared the link what i am trying to achieve, I am open to take suggestion on How to I can approach this. As I am totally new on this Part, not getting the idea of how I should start to achieve this.

Sharing more info

When I open the page the initial route is showing [![Check this image it shows the public route][2]][2]

Now when I scroll on sidebar Overview became active and the overview route shows up [![Check this image][3]][3]

So above I want to achieve.

similarly it goes for all the sidebar menus, now sidebar has some sub menus also, which works exact at the same way, if I am able to achieve with one flow this sub menu I can do by myself. I just need a head start for this.

[My code sandbox link][4]

How to check for sub menu and open when menu is active

Actually my data have some sub menus

    [
    {
        menu: 'HOME',
        path: 'home',
        data:
            "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
    },
    {
        menu: 'PROFILE',
        path: 'profile',
        data:
            "The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from 'de Finibus Bonorum et Malorum' by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.",
        Sub_menu: [ // some menus have submenus also
            {
                menu: 'Profile1',
                path: '/profile/profile1',
                data: 'Some data for the sub menu',
            },
            {
                menu: 'Profile2',
                path: '/profile/profile2',
                data: 'Some data for the sub menu 2',
            },
        ],
    },
    {
        menu: 'STATUS',
        path: 'status',
        data:
            "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    },
    {
        menu: 'INFO',
        path: 'info',
        data:
            "Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). q",
        Sub_menu: [
            {
                menu: 'info1',
                path: '/info/info1',
                data: 'Some data for the sub menu info',
            },
            {
                menu: 'info2',
                path: '/info/info2',
                data: 'Some data for the sub menu info2',
            },
        ],
    },
];

[![When Menu having sub menu is active][5]][5]

[![When sub menu is active route changes as usual][6]][6]

Answer

The implementation is about three stuff:

  1. NavBar
  2. Router
  3. scrollspy

In the NavBar: a third party library will need here, let’s install it:

npm install react-router-hash-link

Now, implement it:

import {HashLink} from 'react-router-hash-link';

const NavBar = () => (
  <div className="menuBar">
    <div className="mr-auto ml-1">
      {data.map((item) => (
        <li className="nav-item" key={item.path}>
          <HashLink to={`#${item.path}`} smooth={true}>
            {item.menu}
          </HashLink>
        </li>
      ))}
    </div>
  </div>
);

At this time, the NavBar component is done. let’s continue to the second section, Router

You need one component to render all of the data on it:

<Route exact={true} path="/" component={Home} />

In the example Home component, we need a component to render each section:

const Section = ({ title, description, path }) => {
  const history = useHistory();

  useEffect(() => {
    const el = document.getElementById(path);
    const observer = new window.IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          history.push(`#${path}`);
          return;
        }
      },
      {
        root: null,
        threshold: 0.1 // set offset 0.1 means trigger if atleast 10% of element in viewport
      }
    );

    observer.observe(el);
  }, [path, history]);

  return (
    <div style={{ height: "500px" }}>
      <h3 id={path}>{title}</h3>
      <p>{description}</p>
    </div>
  );
};

The most important magic is here, in the useEffect hook where the currently active section has been watched. let’s use the NavBar and Section components together:

const App = () => {
  return (
    <div>
      <div>
        <NavBar />
      </div>
      <div>
        {data.map((item) => (
          <Section
            title={item.menu}
            description={item.data}
            path={item.path}
            key={item.path}
          />
        ))}
      </div>
    </div>
  );
};

export default App;

Also, you can check out the simple version on codesandbox.