A Look at React Hooks: useRef to Scroll to an Element

A Look at React Hooks: useRef to Scroll to an Element

Let's learn a useful application of the useRef Hook! Scrolling to a page element in React has become so much easier with this Hook

Welcome to another article of A Look at React Hooks, a beginner-friendly series on React Hooks. In this article, let's look at a simple application of the useRef Hook.

Before reading this, you should have a basic understanding of the useRef Hook. If not, please read the Introduction to useRef article first.

In this article, I will show you how to use the useRef Hook to create links in your app to scroll to any section on a web page like this:

1.gif

Let's get started!

Step 1: Create React App + Install Package

First, we create a React app. You can use ViteJS or anything you want. For beginners, you can copy this line instead:

npx create-react-app my-app-name

Then, we install the package we need react-router-dom.

npm install react-router-dom

Step 2: Create the section components

For this simple tutorial, let's create 3 components that will represent the page sections we will scroll to: Main, About and Usage.

In App.js, we import what we need from the 'react-router-dom' package.

import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";

Then, we create our components, which will be the sections in our single page app.

//Main component
function Main() {
  return (
    <div style={{backgroundColor:"lightyellow", minHeight:"100vh"}}>
      <h2>Main</h2>
      <li><Link to="/#about">About</Link></li>
      <li><Link to="/#how-to-use">How To Use</Link></li>
    </div>
  );
}
//About component
function About() {
  return (
    <div style={{backgroundColor:"cornflowerblue", minHeight:"100vh"}}>
      <h2>About Section</h2>
      <li><Link to="/#main">Scroll To Main</Link></li>
      <li><Link to="/#how-to-use">How To Use</Link></li>
    </div>
  );
}
//How to Use component
function Usage() {
  return (
    <div style={{backgroundColor:"coral", minHeight:"100vh"}}>
      <h2>How to Use Section</h2>
      <li><Link to="/#main">Scroll To Main</Link></li>
      <li><Link to="/#about">About</Link></li>
    </div>
  );
}

Step 3: Assemble components

Now we can add these components into the App component and set up React Router components like so:

function App() {
  return (
    <Router>
      <Routes>
        <Route exact path={["/", "/#about", "/#how-to-use"]}>
          <Main/>
          <About/>
          <Use/>
        </Route>
      </Routes>
    </Router>
  );
}

export default App;

If you're not sure how React Router v6 works, please visit their official documentation.

Here's what we should have so far:

mid.gif

Step 4: Add useRef in App

Now here's where the magic begins!

Import useRef at the top of our App.js file:

import React, { useRef } from "react";

Let's initialize the refs for the sections we want our webpage to be able to scroll to. Add these 3 refs in our App. Next, we pass them as props in all 3 section components.

function App() {
  const mainRef = useRef(null); //represents main section
  const aboutRef = useRef(null); //represents about section
  const usageRef = useRef(null); //represents how to use section

 return (
    <Router>
      <Switch>
        <Route exact path={["/", "/#about", "/#how-to-use"]}>
          {/*pass refs as props*/}
          <Main mainRef={mainRef} aboutRef={aboutRef} usageRef={useRef} />
          <About mainRef={mainRef} aboutRef={aboutRef} usageRef={useRef} />
          <Use mainRef={mainRef} aboutRef={aboutRef} usageRef={useRef} />
        </Route>
      </Switch>
    </Router>
  );
}

Step 5: Assign refs to components

In the Main, About and Usage components, we can access the 3 ref props from the previous step and assign their values to their respective DOM elements.

How it Works

Our useRef Hook initialized the 3 props: mainRef, aboutRef and usageRef asnull in the App component. Now, we are assigning them values to a DOM element by using the ref attribute.

So in this case, we take the mainRef prop and assign it to a DOM element in Main like so:

<div ref={mainRef}>

Here's what the Main component looks like at this point.

function Main({ mainRef, aboutRef, usageRef }) {
  return (
    <div ref={mainRef}>
      <h2>Main</h2>
      <li><Link to="/#about">About</Link></li>
      <li><Link to="/#how-to-use">How To Use</Link></li>
    </div>
  );
}

And we do the same thing to the About and Usage components. Remember to assign to the correct ref props. aboutRef to a DOM element in About and usageRef to a DOM element in Usage.

function About({ mainRef, aboutRef, usageRef }) {
  return (
    <div ref={aboutRef}>
      <h2>About Section</h2>
      <li><Link to="/#main">Scroll To Main</Link></li>
      <li><Link to="/#how-to-use">How To Use</Link></li>
    </div>
  );
}
function Usage({ mainRef, aboutRef, usageRef }) {
  return (
    <div ref={usageRef}>
      <h2>How to Use Section</h2>
      <li><Link to="/#main">Scroll To Main</Link></li>
      <li><Link to="/#about">About</Link></li>
    </div>
  );
}

Step 6: Create Scroll To function

Now that each section component has a reference to access the DOM element, we can create a handleScroll function, where the page will scroll to any ref that is passed as an argument.

const handleScroll = (ref) => {
  window.scrollTo({
    top: ref.offsetTop,
    left: 0,
    behavior: "smooth",
  });
};

As shown in the function above, we are using the window.scrollTo function, where we indicate that we want to scroll to the y-coordinates provided by the offsetTop property of the ref DOM element.

Here is an image to visualize the offsetTop property.

offsetTop.PNG

Image source: javascript.info

Our last step is to simply add this handleScroll function in our Link components so that when the user clicks the link, it will scroll to the corresponding ref element.

Recall that to get the value of the ref, we use ref.current. For example, the value of mainRef is mainRef.current. This will be the ref's value to pass in our handleScroll(ref) function.

And so, let's add the onClick handler to the Link inside the section components like so:

//About Link
<Link to="/#about" onClick={() => {handleScroll(aboutRef.current);}}>
     About
</Link>

//Usage Link
<Link to="/#how-to-use" onClick={() => {handleScroll(usageRef.current);}}>
     How To Use
</Link>

//Main Link
<Link to="/#main" onClick={() => {handleScroll(mainRef.current);}}>
     Scroll To Main
</Link>

So here's our final 3 section components with all the onClick handlers in every Link.

function Main({ mainRef, aboutRef, usageRef }) {
  return (
    <div ref={mainRef}>
      <h2>Main</h2>
      <li><Link to="/#about" onClick={() => {
            handleScroll(aboutRef.current);
          }}>About</Link></li>
      <li><Link to="/#how-to-use" onClick={() => {
            handleScroll(usageRef.current);
          }}>How To Use</Link></li>
    </div>
  );
}
function About({ mainRef, aboutRef, usageRef }) {
  return (
    <div ref={aboutRef}>
      <h2>About Section</h2>
      <li><Link to="/#main" onClick={() => {
            handleScroll(mainRef.current);
          }}>Scroll To Main</Link></li>
      <li><Link to="/#how-to-use" onClick={() => {
            handleScroll(usageRef.current);
          }}>How To Use</Link></li>
    </div>
  );
}
function Usage({ mainRef, aboutRef, usageRef }) {
  return (
    <div ref={usageRef}>
      <h2>How to Use Section</h2>
      <li><Link to="/#main" onClick={() => {
            handleScroll(mainRef.current);
          }}>Scroll To Main</Link></li>
      <li><Link to="/#how-to-use" onClick={() => {
            handleScroll(usageRef.current);
          }}>How To Use</Link></li>
    </div>
  );
}

Result

Let's take a look at the final result! We can now click the links to scroll to any section in the page where we assigned a ref.

final.gif

Conclusion

In this article, we have applied a simple use case of the useRef Hook. I hope it has helped you deepen your understanding of the Hook from the Introduction to useRef article.

Thanks for reading! Please share and like the article if it has been a helpful read. Also, do share in the comments if you'd like me to write more useful applications of other React Hooks. Cheers!


Futher Reading

Did you find this article valuable?

Support Victoria Lo by becoming a sponsor. Any amount is appreciated!

ย