Untitled
raw download clone
TEXT
views 13
,
size 2321 b
/** @jsx jsx */
import { createContext, useEffect } from 'react';
import { RouteComponentProps, useLocation } from 'react-router-dom';
import { jsx } from '@emotion/core';
import styled from '@emotion/styled';
import isEqual from 'react-fast-compare';

import qs from 'query-string';
import { usePrevious } from 'utils';

type PageScrollContextState = {
  updateScroll: () => void;
};

export const PageScrollContext = createContext<PageScrollContextState>({ updateScroll() {} });

const updateScroll = () => {
  window.scrollTo(0, 0);
};

const StyledPageScrollContainer = styled.div<{ isExternalPage: boolean }>`
  height: 100%;

  ${({ isExternalPage }) => {
    return (
      !isExternalPage &&
      `
        margin: 0;
        margin-left: 90px;
        width: calc(100vw - 110px);
    `
    );
  }}
`;

type Props = {
  children: JSX.Element | JSX.Element[];
  isExternalPage: boolean;
};

const IGNORE_SCROLL_QUERY_PARAMS = new Set(['t', 'album', 'photo']);

export const PageScrollContainer: React.FC<Props> = props => {
  const { children, isExternalPage } = props;

  const location = useLocation();
  const prevLocation = usePrevious(location);

  const shouldUpdateScrollOnRouteChange = (
    prevLocation: RouteComponentProps['location'],
    newLocation: RouteComponentProps['location'],
  ): boolean => {
    const pathsDiffer = prevLocation.pathname !== newLocation.pathname;

    if (pathsDiffer) {
      return true;
    }

    const prevQueryParams = qs.parse(prevLocation.search);
    const nextQueryParams = qs.parse(newLocation.search);

    const bothKeys = Array.from(new Set([...Object.keys(prevQueryParams), ...Object.keys(nextQueryParams)]));
    const changedKeys = bothKeys.filter(
      k => !isEqual(prevQueryParams[k], nextQueryParams[k]) || IGNORE_SCROLL_QUERY_PARAMS.has(k),
    );

    return changedKeys.length > 0;
  };

  useEffect(() => {
    if (prevLocation && shouldUpdateScrollOnRouteChange(prevLocation, location)) {
      updateScroll();
    }
  }, [location, prevLocation]);

  return (
    <StyledPageScrollContainer isExternalPage={isExternalPage}>
      <PageScrollContext.Provider value={{ updateScroll }}>{children}</PageScrollContext.Provider>
    </StyledPageScrollContainer>
  );
};
close fullscreen
Login or Register to edit or fork this paste. It's free.