Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do people handle scroll restoration with react-router v4?

Tags:

I'm experiencing some problems with scroll positions on the back button (history popstate) when using react-router. React router v4 doesn't handle scroll management out of the box because browsers are implementing some automatic scroll behavior. This is great except when the height of the browser window changes too dramatically from one view to another. I have implemented the ScrollToTop component as described here: https://reacttraining.com/react-router/web/guides/scroll-restoration

This works great. When you click a link and go to a different component, the browser scrolls to the top (like a normal server-rendered website would). The issue only happens when you go back (via the browser back button) to a view with a much taller window height. It seems that (chrome) tries to go to the scroll position of the previous page before react has rendered the content (and browser height). This results in the scroll only going as far down as it can based on the height of the view it's coming from. Picture this scenario:

View1: Long list of movies (window height 3500px).
(movie is clicked)
View2: Details view of the selected movie (window height: 1000px).
(Browser back button is clicked)
Back to view 1, but scroll position can't go further than 1000px, because chrome is trying to set the position before react renders the long movie list.

For some reason this is only a problem in Chrome. Firefox and Safari seem to handle it fine. I wonder if anyone else have had this problem, and how you guys generally handle scroll restoration in React.

Note: all the movies are imported from a sampleMovies.js — so I'm not waiting for an API response in my example.

like image 582
Malibur Avatar asked Jul 07 '17 12:07

Malibur


People also ask

How do you prevent people from going back in React Dom Router?

Using componentDidUpdate method of React page lifecycle, you can handled or disabled go back functionality in browser. basically componentDidUpdate method will call automatocally when component got updated. so once your component is updated you can prevent to go back as below.

Is React Router deprecated?

This feature has been deprecated because the new structure of Routes is that they should act like components, so you should take advantage of component lifecycle methods instead.

What are two ways of handling Redirect with React Router?

Two ways to handle redirecting on a user event such as create, update and delete with React Router.

What is history scrollRestoration?

scrollRestoration. The scrollRestoration property of History interface allows web applications to explicitly set default scroll restoration behavior on history navigation.


1 Answers

Note that history.scrollRestoration is just a way of disabling the browser's automatic attempts at scroll restoration, which mostly don't work for single-page apps, so that they don't interfere with whatever the app wants to do. In addition to switching to manual scroll restoration, you need some sort of library that provides integration between the browser's history API, React's rendering, and the scroll position of the window and any scrollable block elements.

After not being able to find such a scroll restoration library for React Router 4, I created one called react-scroll-manager. It supports scrolling to top on navigation to a new location (aka history push) and scroll restoration on back/forward (aka history pop). In addition to scrolling the window, it can scroll any nested element that you wrap in an ElementScroller component. It also supports delayed/asynchronous rendering by using a MutationObserver to watch the window/element content up to a user-specified time limit. This delayed rendering support applies to scroll restoration as well as scrolling to a specific element using a hash link.

npm install react-scroll-manager

import React from 'react'; import { Router } from 'react-router-dom'; import { ScrollManager, WindowScroller, ElementScroller } from 'react-scroll-manager'; import { createBrowserHistory as createHistory } from 'history';  class App extends React.Component {   constructor() {     super();     this.history = createHistory();   }   render() {     return (       <ScrollManager history={this.history}>         <Router history={this.history}>           <WindowScroller>             <ElementScroller scrollKey="nav">               <div className="nav">                 ...               </div>             </ElementScroller>             <div className="content">               ...             </div>           </WindowScroller>         </Router>       </ScrollManager>     );   } } 

Note that an HTML5 browser (10+ for IE) and React 16 are required. HTML5 provides the history API, and the library uses the modern Context and Ref APIs from React 16.

like image 197
Trevor Robinson Avatar answered Oct 19 '22 20:10

Trevor Robinson