UNPKG

found-scroll

Version:
93 lines (76 loc) 2.6 kB
import StateStorage from 'farce/StateStorage'; import React, { Component, createContext } from 'react'; import ScrollBehavior from 'scroll-behavior'; const STORAGE_NAMESPACE = '@@scroll'; export const ScrollContext = /*#__PURE__*/createContext(null); const defaultCreateScrollBehavior = config => new ScrollBehavior(config); class ScrollManager extends Component { constructor(props) { super(props); this.prevRenderArgs = null; this.shouldUpdateScroll = (prevRenderArgs, renderArgs) => { const { shouldUpdateScroll } = this.props; if (!shouldUpdateScroll) { return true; } // Hack to allow access to ScrollBehavior internals (e.g. stateStorage). return shouldUpdateScroll.call(this.scrollBehavior, prevRenderArgs, renderArgs); }; this.registerScrollElement = (key, element) => { const { renderArgs } = this.props; this.scrollBehavior.registerElement(key, element, this.shouldUpdateScroll, renderArgs); return () => { this.scrollBehavior.unregisterElement(key); }; }; const { createScrollBehavior = defaultCreateScrollBehavior, renderArgs: _renderArgs } = props; const { router } = _renderArgs; this.scrollBehavior = createScrollBehavior({ addNavigationListener: router.addNavigationListener, stateStorage: new StateStorage(router, STORAGE_NAMESPACE), getCurrentLocation: () => this.props.renderArgs.location, shouldUpdateScroll: this.shouldUpdateScroll }); this.scrollContext = { scrollBehavior: this.scrollBehavior, registerScrollElement: this.registerScrollElement }; this.prevRenderArgs = null; } componentDidMount() { this.maybeUpdateScroll(); } componentDidUpdate() { this.maybeUpdateScroll(); } componentWillUnmount() { this.scrollBehavior.stop(); } maybeUpdateScroll() { const { renderArgs } = this.props; const prevLocation = this.prevRenderArgs && this.prevRenderArgs.location; if (renderArgs.location === prevLocation || !(renderArgs.elements || renderArgs.error)) { // If the location hasn't actually changed, or if we're in a global // pending state, don't update the scroll position. return; } this.scrollBehavior.updateScroll(this.prevRenderArgs, renderArgs); this.prevRenderArgs = renderArgs; } render() { return /*#__PURE__*/React.createElement(ScrollContext.Provider, { value: this.scrollContext }, this.props.children); } } export default ScrollManager;