Scroll Restoration Between Pages

Loading

Scroll Restoration Between Pages in React

In single-page applications (SPAs) like those built with React, users often navigate between different routes, and when they go back to a previous page, they expect to see the content exactly as it was. One common behavior that is important for a seamless user experience is scroll restoration — preserving the scroll position when users navigate between pages.

React Router (especially in combination with React’s state management) doesn’t automatically handle scroll restoration. However, we can implement it manually to ensure the scroll position is maintained across page transitions.

Here’s how you can implement scroll restoration in React:


1. Scroll Restoration with window.scrollTo() and useEffect

React Router v6+ doesn’t handle scroll restoration by default, but you can implement it yourself using the useEffect hook and window.scrollTo().

Example: Basic Scroll Restoration

  1. Using useEffect for Scroll Restoration

In this example, we will scroll the page back to the top when navigating to a new route, and also save the scroll position before navigating away.

import React, { useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useLocation } from 'react-router-dom';

const HomePage = () => {
  return <div style={{ height: '1500px' }}><h1>Home Page</h1></div>;
};

const AboutPage = () => {
  return <div style={{ height: '1500px' }}><h1>About Page</h1></div>;
};

const ScrollToTop = () => {
  const location = useLocation();

  useEffect(() => {
    // Scroll to top when the location changes
    window.scrollTo(0, 0);
  }, [location]);

  return null;
};

const App = () => {
  return (
    <Router>
      <ScrollToTop />
      <nav>
        <Link to="/">Home</Link> | <Link to="/about">About</Link>
      </nav>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/about" element={<AboutPage />} />
      </Routes>
    </Router>
  );
};

export default App;

Explanation:

  • window.scrollTo(0, 0): Whenever the route changes (i.e., when the location changes), we scroll the page to the top (position 0,0).
  • useEffect: This hook is triggered every time the location (the current route) changes.
  • useLocation(): This hook provides access to the current location (i.e., the URL) in the app, allowing us to detect route changes.

2. Preserve Scroll Position on Route Navigation

If you want to preserve the scroll position on route changes (e.g., if a user scrolls down on a page and goes back, you want to return to the same scroll position), you can store the scroll position in state and restore it when the user navigates back.

Example: Preserve and Restore Scroll Position

import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useLocation } from 'react-router-dom';

const HomePage = () => {
  return <div style={{ height: '1500px' }}><h1>Home Page</h1></div>;
};

const AboutPage = () => {
  return <div style={{ height: '1500px' }}><h1>About Page</h1></div>;
};

const ScrollToTop = () => {
  const [scrollPositions, setScrollPositions] = useState({});
  const location = useLocation();

  useEffect(() => {
    // Save scroll position on each page
    setScrollPositions(prevPositions => ({
      ...prevPositions,
      [location.pathname]: window.scrollY,
    }));
  }, [location]);

  useEffect(() => {
    // Restore scroll position if it exists for the current page
    if (scrollPositions[location.pathname] !== undefined) {
      window.scrollTo(0, scrollPositions[location.pathname]);
    } else {
      window.scrollTo(0, 0); // Default to top if no scroll position is stored
    }
  }, [location, scrollPositions]);

  return null;
};

const App = () => {
  return (
    <Router>
      <ScrollToTop />
      <nav>
        <Link to="/">Home</Link> | <Link to="/about">About</Link>
      </nav>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/about" element={<AboutPage />} />
      </Routes>
    </Router>
  );
};

export default App;

Explanation:

  • Scroll Positions State: scrollPositions stores the scroll positions for each route, indexed by the pathname.
  • First useEffect: This saves the current scroll position (window.scrollY) whenever the route changes.
  • Second useEffect: This restores the scroll position for the current route if it’s available in the scrollPositions state.

3. Scroll Restoration on Back/Forward Navigation

By default, browsers automatically restore the scroll position when the user navigates back to a previously visited page. If you need more control or wish to customize this behavior, you can manage the scroll position manually using the popstate event.

Example: Advanced Scroll Restoration with popstate

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

const HomePage = () => {
  return <div style={{ height: '1500px' }}><h1>Home Page</h1></div>;
};

const AboutPage = () => {
  return <div style={{ height: '1500px' }}><h1>About Page</h1></div>;
};

const App = () => {
  useEffect(() => {
    // Listen for browser back/forward navigation to restore scroll position
    const handlePopState = () => {
      const scrollY = sessionStorage.getItem(window.location.pathname);
      if (scrollY !== null) {
        window.scrollTo(0, parseInt(scrollY, 10));
      }
    };

    window.addEventListener('popstate', handlePopState);

    return () => {
      window.removeEventListener('popstate', handlePopState);
    };
  }, []);

  useEffect(() => {
    // Save the scroll position whenever the route changes
    const saveScrollPosition = () => {
      sessionStorage.setItem(window.location.pathname, window.scrollY);
    };

    window.addEventListener('beforeunload', saveScrollPosition);
    return () => window.removeEventListener('beforeunload', saveScrollPosition);
  }, []);

  return (
    <Router>
      <nav>
        <Link to="/">Home</Link> | <Link to="/about">About</Link>
      </nav>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/about" element={<AboutPage />} />
      </Routes>
    </Router>
  );
};

export default App;

Explanation:

  • Saving Scroll Position: Using sessionStorage, the scroll position is saved whenever the user leaves the page (or navigates away).
  • Restoring Scroll Position: When the user goes back to a page, the popstate event is triggered, and we restore the scroll position from sessionStorage.
  • sessionStorage: Stores data for the duration of the page session. It will be cleared when the page or tab is closed.

4. Using Third-Party Libraries for Scroll Restoration

There are third-party libraries such as react-router-scroll-4 or react-scroll-restoration that can handle scroll restoration automatically for React Router. These libraries provide an easy way to manage scroll behavior, but they may require additional configuration and setup.


Leave a Reply

Your email address will not be published. Required fields are marked *