How do people handle scroll recovery using action-router v4?

I'm having problems with scroll positions on the back button (pop-up history) when using the react router. React router v4 does not handle scroll control out of the box because browsers implement some automatic scroll behavior. This is great if the height of the browser window changes too much from one look to another. I implemented the ScrollToTop component as described here: https://reacttraining.com/react-router/web/guides/scroll-restoration

This works great. When you click the link and go to another component, the browser scrolls up (for example, a regular website processed by a server). The problem arises when you return (via the back button of the browser) to a view with a much higher window height. It seems that (chrome) is trying to move to the scroll position of the previous page before the reaction displays the content (and browser height). This causes the scroll to go as far as possible based on the height of the view. Introduce this scenario:

View1: A long list of films (window height 3500 pixels).
(click on click)
View2 : detailed view of the selected movie (window height: 1000 pixels).
("Back in browser" button pressed)
Back to view 1 , but the scroll position cannot exceed 1000 pixels, because chrome tries to set a position before reacting, it will display a long list of movies.

For some reason, this is just a problem in Chrome. Firefox and Safari seem to be handling this. I wonder if anyone else has this problem, and how you guys usually handle scroll recovery in React.

Note: all movies are imported from sampleMovies.js - so I do not expect an API response in my example.

+14
reactjs react-router
source share
3 answers

How do you handle scroll recovery?

Turns out browsers have implementations of history.scrollRestoration.

Maybe you can use this? Check out these links.

https://developer.mozilla.org/en/docs/Web/API/History#Specifications https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration

Also, I found an npm module that could easily handle scroll recovery, but this library only works with responsive router v3 and below

https://www.npmjs.com/package/react-router-restore-scroll https://github.com/ryanflorence/react-router-restore-scroll

Hope this helps.

+2
source share

Please note that history.scrollRestoration is just a way to turn off automatic scrolling recovery attempts in the browser, which basically do not work for single-page applications so that they do not interfere with the application. In addition to switching to manual recovery by scrolling, you will need some kind of library that provides integration between the browser history API, React rendering and the window's scroll position and any elements of the scrollable block.

After I could not find such a scroll recovery library for React Router 4, I created one of them, called the react-scroll-manager . It supports scrolling to the top when moving to a new place (also known as a push of history) and restoring scroll back / forward (also known as history). In addition to scrolling the window, it can scroll any nested element that you transfer to the ElementScroller component. It also supports deferred / asynchronous rendering using MutationObserver to view the contents of a window / element up to a user-specified time limit. This support for deferred rendering applies to scrolling 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 HTML5 (10+ for IE) and React 16 are required. HTML5 provides a history API, and the library uses the modern Context and Ref APIs from React 16.

+3
source share

I used localStorage to track scroll position - not sure if this works for all situations.

In this example, there is a company page with a set of stores, and each store has a set of storefronts. I needed to track the scroll position in storefronts, so I saved this in storeScrollTop key. There were 6 lines of code to add.

company.jsx:

 // click on a store link const handleClickStore = (evt) => { window.localStorage.removeItem('storeScrollTop') // <-- reset scroll value const storeId = evt.currentTarget.id history.push('/store/${storeId}') } 

store.jsx:

 // initialize store page React.useEffect(() => { // fetch displays getStoreDisplays(storeId).then(objs => setObjs(objs)).then(() => { // get the 'store' localstorage scrollvalue and scroll to it const scrollTop = Number(window.localStorage.getItem('storeScrollTop') || '0') const el = document.getElementsByClassName('contents')[0] el.scrollTop = scrollTop }) }, [storeId]) // click on a display link const handleClickDisplay = (evt) => { // save the scroll pos for return visit const el = document.getElementsByClassName('contents')[0] window.localStorage.setItem('storeScrollTop', String(el.scrollTop)) // goto the display const displayId = evt.currentTarget.id history.push('/display/${displayId}') } 
0
source share

All Articles