Restore Scroll

Restore the scroll positions of window
and scrollable elements when
the user navigates around a React Router app.

Updates for this fork
This is a fork of jshin49/react-router-restore-scroll.
The original library created by Ryan Florence seems to be unmaintained so @jshin49 forked it to support React v16 and fix some other minor issues.
We recommend using node v8.1.2 and the latest npm version in order to use this version, and to use react-router@3.
Major updates:
- Removed deprecated usages of React.createClass and React.PropTypes in order to support React v16.
import React from 'react'
const RestoreScroll = React.createClass({
...
propTypes: {
scrollKey: React.PropTypes.string.isRequired
},
...
)}
import React from 'react'
import PropTypes from 'prop-types'
import createReactClass from 'create-react-class'
const RestoreScroll = createReactClass({
...
propTypes: {
scrollKey: PropTypes.string.isRequired
},
...
)}
Referring to
- Fixed this repo to directly allow installation with npm (post installation script).
- Fixed wrong link in
package.json
- Fixed not restoring scroll for the first
POP
action.
- Only save scroll position when
PUSH
or REPLACE
action.
Installation:
npm install @ridi/react-router-restore-scroll
or
Add the following in your package.json
...
"react-router-restore-scroll": "@ridi/react-router-restore-scroll",
...
and run npm install
. If there's an error, remove the node_modules
file and try installing again.
Temporarily a Plugin
Plan is to put this into React Router directly, but for now you can plug
it in and help us get the bugs out (and write some tests, there aren't
any yet!)
Usage
import React from 'react'
import { render } from 'react-dom'
import { Router, browserHistory, applyRouterMiddleware } from 'react-router'
import routes from './routes'
import {
useHistoryRestoreScroll,
useRouterRestoreScroll
} from 'react-router-restore-scroll'
const createHistory = useHistoryRestoreScroll(() => browserHistory)
const routerRender = applyRouterMiddleware(
useRouterRestoreScroll()
)
render(
<Router
history={createHistory()}
render={routerRender}
routes={routes}
/>,
document.getElementById('app')
)
Now the window's scroll positions will be automatically restored as you
navigate around in a React Router app, and even when you navigate out of
and back into it from external sites.
Restores Scrollable Elements Too
If you’ve got scrollable elements (overflow: auto|scroll
) they can
also be restored with the RestoreScroll
component.
import { RestoreScroll } from 'react-router-restore-scroll'
<RestoreScroll scrollKey="one">
<div style={{ height: '200px', overflow: 'auto', border: '1px solid' }}>
<div style={{ height: '100px', background: 'hsl(0, 50%, 90%)' }}>scroll me</div>
<div style={{ height: '100px', background: 'hsl(100, 50%, 90%)' }}>two</div>
<div style={{ height: '100px', background: 'hsl(200, 50%, 90%)' }}>three</div>
</div>
</RestoreScroll>
Non-React usage
The useHistoryRestoreScroll
enhancer gives you a history with a
restoreScroll
property with three methods that you can use to
integrate into any view layer that uses history
(cycle.js, etc.).
import createBrowserHistory from 'history/lib/createBrowserHistory'
import useHistoryRestoreScroll from 'react-router-restore-scroll/lib/useHistoryRestoreScroll'
const history = useHistoryRestoreScroll(createBrowserHistory)()
history.restoreScroll.registerScroller(scrollKey, domNode)
history.restoreScroll.unregisterScroller(scrollKey)
history.restoreScroll.restoreWindow()
You can look at modules/RestoreWindowScroll.js
and modules/RestoreScroll.js
to see at which points in a React app these methods are all called.
We'll pull useHistoryRestoreScroll
out into it's own package on npm
eventually so that this use-case isn't required to bring in stuff that
depends on React and React Router.
- It ties into the router middleware to decide when to restore scroll
positions so we don't need workarounds for async routes
- It restores scroll position of individual elements in addition to the
window.
- It doesn't rely on
location.key
in preparation for history 3.0
- It does not have
shouldUpdateScroll
, but once route is on
context we'll be
able to implement the old ignoreScroll
route prop or maybe a function like shouldUpdateScroll
instead.