Last active
September 5, 2020 16:46
-
-
Save ryanflorence/39a37a85254159fd7a5ca54027e175dc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { Location } from "@reach/router"; | |
let scrollPositions = {}; | |
class ManageScrollImpl extends React.Component { | |
componentDidMount() { | |
try { | |
// session storage will throw for a few reasons | |
// - user settings | |
// - in-cognito/private browsing | |
// - who knows... | |
let storage = JSON.parse(sessionStorage.getItem("scrollPositions")); | |
if (storage) { | |
scrollPositions = JSON.parse(storage) || {}; | |
let { key } = this.props.location; | |
if (scrollPositions[key]) { | |
window.scrollTo(0, scrollPositions[key]); | |
} | |
} | |
} catch (e) {} | |
window.addEventListener("scroll", this.listener); | |
} | |
componentWillUnmount() { | |
window.removeEventListener("scroll", this.listener); | |
} | |
componentDidUpdate() { | |
const { key } = this.props.location; | |
if (!scrollPositions[key]) { | |
// never seen this location before | |
window.scrollTo(0, 0); | |
} else { | |
// seen it | |
window.scrollTo(0, scrollPositions[key]); | |
} | |
} | |
listener = () => { | |
scrollPositions[this.props.location.key] = window.scrollY; | |
try { | |
sessionStorage.setItem( | |
"scrollPositions", | |
JSON.stringify(scrollPositions) | |
); | |
} catch (e) {} | |
}; | |
render() { | |
return null; | |
} | |
} | |
export default () => ( | |
<Location> | |
{({ location }) => <ManageScrollImpl location={location} />} | |
</Location> | |
); |
Why not refactor componentDidUpdate block to:
const vistedLocationPosition = scrollPositions[this.props.location.key]
window.scrollTo(0, vistedLocationPosition || 0)
For anyone looking for a functional component version of managing scroll position. I just import this component below my router <Router>...routes</Router><ManageScroll />
import { Location, WindowLocation } from "@reach/router";
import React from "react";
let scrollPositions: { [key: string]: number } = {};
type Props = {
location: WindowLocation;
}
const ManageScrollImpl = ({ location }: Props) => {
React.useEffect(() => {
if (location.href) {
window.scrollTo(0, scrollPositions[location.href || 0]);
}
window.addEventListener('scroll', listener);
return () => window.removeEventListener('scroll', listener);
}, [location?.href])
const listener = () => {
if (location && location.href) {
scrollPositions[location.href] = window.scrollY;
}
};
return null;
}
export const ManageScroll = () => (
<Location>
{({ location }) => <ManageScrollImpl location={location} />}
</Location>
);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is there any performance loss from having the listener constantly write to sessionStorage? Shouldn't it be possible to only update storage when I'm changing routes?