How To Handle Scroll Position Like A Pro In React

Rehan Pinjari
6 min readAug 29, 2024

--

Setting Scroll Position in React

Scrolling is one of those things that stays ignored until it stops working as expected. Have you ever found yourself scrolling back to the top after each route change, or losing your place in a long post when you press refresh?

Yes, scroll position is more important than you might think! In this post, we’ll look at how to handle scroll positions in React to ensure your users never lose their place.

Grab a snack because this is going to be exciting!

Why does the scrolling position matter? Think of it like a bookmark in a book; it allows users to find the data you provide.

Consider reading a novel in which it restarts from the first page every time you close the book. Isn’t this annoying? The same goes for web apps.

Whether it’s preserving scroll position after a page reload or keeping everything in place when moving within single-page applications, scroll position management might significantly boost the user experience.

Real-world scenarios include a few things:

  • Preserving scroll position: After a page reloads, users will not lose where they were.
  • Navigating SPAs: When moving between views, be sure you are scrolling in the exact area.
  • Infinite scrolling: Maintaining position when dynamically loading content.

Basics of Scroll Position in React

So, how does your browser handle scrolling by default? Simple as that, it does not care. Without mentioning a certain way, the scroll position resets.

Luckily, JavaScript has essential DOM methods for solving this, such as window.scrollTo, window.scroll, and window.scrollBy.

They work well, but they aren’t exactly a party trick.

// Scroll to the top
window.scrollTo(0, 0);

// Scroll by a specific amount
window.scrollBy(0, 100); // Scrolls down by 100px

These are the basic blocks, but in a React world, we need somewhat more improvements.

React Refs and DOM Manipulation

Welcome to React Refs, your sneak peek at the DOM. Refs let you access and change DOM components directly, which is useful when you must define scroll positions.

Here’s a simple guide for using Refs.

  1. Create a ref using React.createRef() or useRef() if you're using functional components.
  2. Attach the ref to your scrollable component.
  3. Use DOM methods to manipulate the scroll position of the ref’s current property.

Example for vertical scroll control:

import React, { useRef } from 'react';

const ScrollComponent = () => {
// Create a reference for the scrollable div
const scrollRef = useRef(null);

// Function to scroll the div to the top
const scrollToTop = () => {
// Check if the scrollRef is defined and scroll to the top
if (scrollRef.current) {
scrollRef.current.scrollTop = 0;
}
};

return (
<div>
{/* Scrollable container with a reference attached */}
<div ref={scrollRef} style={{ overflowY: 'scroll', height: '200px', border: '1px solid #ddd' }}>
{/* Content inside the scrollable container */}
<div style={{ height: '1000px', padding: '10px' }}>
Scroll down and click the button to go to the top!
</div>
</div>
{/* Button to trigger scroll to top functionality */}
<button onClick={scrollToTop} style={{ marginTop: '10px', padding: '5px 10px', cursor: 'pointer' }}>
Scroll to Top
</button>
</div>
);
};

export default ScrollComponent;

Using State and Effects to Manage Scroll Position

React’s useState and useEffect hooks work like Batman and Robin in terms of scroll position handling.

Scroll positions can be saved in state and restored on component mounting.

import React, { useState, useEffect } from 'react';

const ScrollSaver = () => {
// State to store the current scroll position
const [scrollPos, setScrollPos] = useState(0);

// Effect to update scrollPos state when the user scrolls
useEffect(() => {
const handleScroll = () => setScrollPos(window.scrollY);

// Adding scroll event listener
window.addEventListener('scroll', handleScroll);

// Cleanup function to remove the event listener
return () => window.removeEventListener('scroll', handleScroll);
}, []);

// Effect to restore scroll position on component mount
useEffect(() => {
// Scroll to the saved position
window.scrollTo(0, scrollPos);
}, [scrollPos]);

return (
<div style={{ height: '1500px', padding: '20px' }}>
<h1>Scroll and Refresh</h1>
<p>Scroll down, refresh the page, and see the magic!</p>
</div>
);
};

export default ScrollSaver;

This approach helps you to maintain the perfect scroll position like an expert. Set and remember your goals, just like at the gym.

Handling Scroll Position on Route Change

Navigating routes in React can feel like a scroll reset nightmare. React Router does not manage scroll positions by default, but with some JavaScript skills, you can change that.

Resetting scroll on route change:

// Import necessary hooks from React and React Router
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

// Define a functional component named ScrollToTop
const ScrollToTop = () => {
// Extract the current pathname from the location object
const { pathname } = useLocation();

// useEffect hook to perform side effects
useEffect(() => {
// Scroll the window to the top whenever the pathname changes
window.scrollTo(0, 0);
}, [pathname]); // The effect runs whenever 'pathname' changes

// The component doesn't render any visible UI, so it returns null
return null;
};

// Export the ScrollToTop component as the default export
export default ScrollToTop;

Adding this component to your App component is similar to using a skilled scroll waiter. He has you covered every time.

Custom Hooks for Scroll Position

Why stop with basic scroll control when you can make reusable custom hooks? Let’s create a useScrollPosition hook.

import { useEffect, useState } from 'react';

// Custom hook to track the scroll position of the window
const useScrollPosition = () => {
// State to store the current scroll position
const [scrollPosition, setScrollPosition] = useState(0);

useEffect(() => {
// Function to update the scroll position state
const updatePosition = () => setScrollPosition(window.scrollY);

// Adding the event listener to track scroll events
window.addEventListener('scroll', updatePosition);

// Cleanup function to remove the event listener when the component unmounts
return () => window.removeEventListener('scroll', updatePosition);
}, []); // Empty dependency array ensures this effect runs only once on mount

// Return the current scroll position
return scrollPosition;
};

export default useScrollPosition;

This custom hook not only cleans up your code, but also improves your component with scroll scroll-tracking feature.

Handling Scroll Position in Complex Layouts

Nested scrolling fields? Don’t worry! Use CSS features like overflow lightly, and handle individual scroll positions via refs.

// Add scroll management to complex layouts using React
import React, { useRef } from 'react';

const ComplexLayout = () => {
// Create a ref to reference the scrollable container
const containerRef = useRef(null);

// Function to scroll to the bottom of the container
const scrollToBottom = () => {
// Scroll to the bottom of the container by setting scrollTop to the container's scrollHeight
containerRef.current.scrollTop = containerRef.current.scrollHeight;
};

return (
<div
ref={containerRef} // Attach the ref to the container div
style={{
overflowY: 'scroll', // Enable vertical scrolling
height: '300px', // Set fixed height for the scrollable area
border: '1px solid #ccc', // Optional: Add a border for better visibility
padding: '10px' // Optional: Add some padding
}}
>
{/* Content goes here with height exceeding the container to enable scrolling */}
<div style={{ height: '600px' }}>Content goes here</div>

{/* Button to trigger scrolling to the bottom */}
<button onClick={scrollToBottom} style={{ marginTop: '10px' }}>
Scroll to Bottom
</button>
</div>
);
};

export default ComplexLayout;

Final Words

Scroll handling in React needs more than just creating a window.scrollTo. Whether it’s through basic DOM manipulation, React Refs, custom hooks, or third-party frameworks, there’s a solution for every scenario.

Key Takeaways:

  • Understand your scrolling needs before choosing a solution.
  • React’s hooks and Refs offer more accurate control.
  • Don’t ignore performance or accessibility.
  • Try different scroll positions to see what works best for you.

So, the next time you find yourself scrolling constantly, remember that it doesn’t have to be like this. If you loved this post, please clap and follow me for more tips!

Thank you for reading! Clap if you found value here and follow for more.

--

--