Commit 0f710c19 authored by tom's avatar tom

refactor scroll direction context

parent 7bc58a3f
...@@ -2,22 +2,27 @@ import clamp from 'lodash/clamp'; ...@@ -2,22 +2,27 @@ import clamp from 'lodash/clamp';
import throttle from 'lodash/throttle'; import throttle from 'lodash/throttle';
import React from 'react'; import React from 'react';
const ScrollDirectionContext = React.createContext<'up' | 'down' | null>(null);
import isBrowser from 'lib/isBrowser'; import isBrowser from 'lib/isBrowser';
const SCROLL_DIFF_THRESHOLD = 20; const SCROLL_DIFF_THRESHOLD = 20;
type Directions = 'up' | 'down'; type Directions = 'up' | 'down';
export default function useScrollDirection() { interface Props {
children: React.ReactNode;
}
export function ScrollDirectionProvider({ children }: Props) {
const prevScrollPosition = React.useRef(isBrowser() ? window.pageYOffset : 0); const prevScrollPosition = React.useRef(isBrowser() ? window.pageYOffset : 0);
const [ scrollDirection, setDirection ] = React.useState<Directions>(); const [ scrollDirection, setDirection ] = React.useState<Directions | null>(null);
const handleScroll = React.useCallback(() => { const handleScroll = React.useCallback(() => {
const currentScrollPosition = clamp(window.pageYOffset, 0, window.document.body.scrollHeight - window.innerHeight); const currentScrollPosition = clamp(window.pageYOffset, 0, window.document.body.scrollHeight - window.innerHeight);
const scrollDiff = currentScrollPosition - prevScrollPosition.current; const scrollDiff = currentScrollPosition - prevScrollPosition.current;
if (window.pageYOffset === 0) { if (window.pageYOffset === 0) {
setDirection(undefined); setDirection(null);
} else if (Math.abs(scrollDiff) > SCROLL_DIFF_THRESHOLD) { } else if (Math.abs(scrollDiff) > SCROLL_DIFF_THRESHOLD) {
setDirection(scrollDiff < 0 ? 'up' : 'down'); setDirection(scrollDiff < 0 ? 'up' : 'down');
} }
...@@ -37,5 +42,17 @@ export default function useScrollDirection() { ...@@ -37,5 +42,17 @@ export default function useScrollDirection() {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
return scrollDirection; return (
<ScrollDirectionContext.Provider value={ scrollDirection }>
{ children }
</ScrollDirectionContext.Provider>
);
}
export function useScrollDirection() {
const context = React.useContext(ScrollDirectionContext);
if (context === undefined) {
throw new Error('useScrollDirection must be used within a ScrollDirectionProvider');
}
return context;
} }
...@@ -7,19 +7,16 @@ import React, { useState } from 'react'; ...@@ -7,19 +7,16 @@ import React, { useState } from 'react';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import { AppContextProvider } from 'lib/appContext'; import { AppContextProvider } from 'lib/appContext';
import { Chakra } from 'lib/Chakra'; import { Chakra } from 'lib/Chakra';
import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection';
import useConfigSentry from 'lib/hooks/useConfigSentry'; import useConfigSentry from 'lib/hooks/useConfigSentry';
import type { ErrorType } from 'lib/hooks/useFetch'; import type { ErrorType } from 'lib/hooks/useFetch';
import useScrollDirection from 'lib/hooks/useScrollDirection';
import { SocketProvider } from 'lib/socket/context'; import { SocketProvider } from 'lib/socket/context';
import theme from 'theme'; import theme from 'theme';
import ScrollDirectionContext from 'ui/ScrollDirectionContext';
import AppError from 'ui/shared/AppError/AppError'; import AppError from 'ui/shared/AppError/AppError';
import ErrorBoundary from 'ui/shared/ErrorBoundary'; import ErrorBoundary from 'ui/shared/ErrorBoundary';
function MyApp({ Component, pageProps }: AppProps) { function MyApp({ Component, pageProps }: AppProps) {
useConfigSentry(); useConfigSentry();
const directionContext = useScrollDirection();
const [ queryClient ] = useState(() => new QueryClient({ const [ queryClient ] = useState(() => new QueryClient({
defaultOptions: { defaultOptions: {
queries: { queries: {
...@@ -62,11 +59,11 @@ function MyApp({ Component, pageProps }: AppProps) { ...@@ -62,11 +59,11 @@ function MyApp({ Component, pageProps }: AppProps) {
<ErrorBoundary renderErrorScreen={ renderErrorScreen } onError={ handleError }> <ErrorBoundary renderErrorScreen={ renderErrorScreen } onError={ handleError }>
<AppContextProvider pageProps={ pageProps }> <AppContextProvider pageProps={ pageProps }>
<QueryClientProvider client={ queryClient }> <QueryClientProvider client={ queryClient }>
<ScrollDirectionContext.Provider value={ directionContext }> <ScrollDirectionProvider>
<SocketProvider url={ `${ appConfig.api.socket }${ appConfig.api.basePath }/socket/v2` }> <SocketProvider url={ `${ appConfig.api.socket }${ appConfig.api.basePath }/socket/v2` }>
<Component { ...pageProps }/> <Component { ...pageProps }/>
</SocketProvider> </SocketProvider>
</ScrollDirectionContext.Provider> </ScrollDirectionProvider>
<ReactQueryDevtools/> <ReactQueryDevtools/>
</QueryClientProvider> </QueryClientProvider>
</AppContextProvider> </AppContextProvider>
......
import React from 'react';
const ScrollDirectionContext = React.createContext<'up' | 'down' | undefined>(undefined);
export default ScrollDirectionContext;
...@@ -2,7 +2,7 @@ import { Flex, useColorModeValue, chakra } from '@chakra-ui/react'; ...@@ -2,7 +2,7 @@ import { Flex, useColorModeValue, chakra } from '@chakra-ui/react';
import throttle from 'lodash/throttle'; import throttle from 'lodash/throttle';
import React from 'react'; import React from 'react';
import ScrollDirectionContext from 'ui/ScrollDirectionContext'; import { useScrollDirection } from 'lib/contexts/scrollDirection';
type Props = { type Props = {
children: React.ReactNode; children: React.ReactNode;
...@@ -15,6 +15,7 @@ const TOP_DOWN = 0; ...@@ -15,6 +15,7 @@ const TOP_DOWN = 0;
const ActionBar = ({ children, className }: Props) => { const ActionBar = ({ children, className }: Props) => {
const [ isSticky, setIsSticky ] = React.useState(false); const [ isSticky, setIsSticky ] = React.useState(false);
const ref = React.useRef<HTMLDivElement>(null); const ref = React.useRef<HTMLDivElement>(null);
const scrollDirection = useScrollDirection();
const handleScroll = React.useCallback(() => { const handleScroll = React.useCallback(() => {
if ( if (
...@@ -41,8 +42,6 @@ const ActionBar = ({ children, className }: Props) => { ...@@ -41,8 +42,6 @@ const ActionBar = ({ children, className }: Props) => {
const bgColor = useColorModeValue('white', 'black'); const bgColor = useColorModeValue('white', 'black');
return ( return (
<ScrollDirectionContext.Consumer>
{ (scrollDirection) => (
<Flex <Flex
className={ className } className={ className }
backgroundColor={ bgColor } backgroundColor={ bgColor }
...@@ -61,8 +60,6 @@ const ActionBar = ({ children, className }: Props) => { ...@@ -61,8 +60,6 @@ const ActionBar = ({ children, className }: Props) => {
> >
{ children } { children }
</Flex> </Flex>
) }
</ScrollDirectionContext.Consumer>
); );
}; };
......
import { HStack, Box, Flex, useColorModeValue } from '@chakra-ui/react'; import { HStack, Box, Flex, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import ScrollDirectionContext from 'ui/ScrollDirectionContext'; import { useScrollDirection } from 'lib/contexts/scrollDirection';
import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo'; import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop'; import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop';
import ProfileMenuMobile from 'ui/snippets/profileMenu/ProfileMenuMobile'; import ProfileMenuMobile from 'ui/snippets/profileMenu/ProfileMenuMobile';
...@@ -17,10 +17,9 @@ type Props = { ...@@ -17,10 +17,9 @@ type Props = {
const Header = ({ hideOnScrollDown, isHomePage }: Props) => { const Header = ({ hideOnScrollDown, isHomePage }: Props) => {
const bgColor = useColorModeValue('white', 'black'); const bgColor = useColorModeValue('white', 'black');
const scrollDirection = useScrollDirection();
return ( return (
<ScrollDirectionContext.Consumer>
{ (scrollDirection) => (
<> <>
<Box bgColor={ bgColor } display={{ base: 'block', lg: 'none' }}> <Box bgColor={ bgColor } display={{ base: 'block', lg: 'none' }}>
<Flex <Flex
...@@ -65,8 +64,6 @@ const Header = ({ hideOnScrollDown, isHomePage }: Props) => { ...@@ -65,8 +64,6 @@ const Header = ({ hideOnScrollDown, isHomePage }: Props) => {
</HStack> </HStack>
) } ) }
</> </>
) }
</ScrollDirectionContext.Consumer>
); );
}; };
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import type { ChangeEvent, FormEvent } from 'react'; import type { ChangeEvent, FormEvent } from 'react';
import searchIcon from 'icons/search.svg'; import searchIcon from 'icons/search.svg';
import ScrollDirectionContext from 'ui/ScrollDirectionContext'; import { useScrollDirection } from 'lib/contexts/scrollDirection';
const TOP = 55; const TOP = 55;
...@@ -17,6 +17,7 @@ interface Props { ...@@ -17,6 +17,7 @@ interface Props {
const SearchBarMobile = ({ onChange, onSubmit, withShadow }: Props) => { const SearchBarMobile = ({ onChange, onSubmit, withShadow }: Props) => {
const [ isSticky, setIsSticky ] = React.useState(false); const [ isSticky, setIsSticky ] = React.useState(false);
const scrollDirection = useScrollDirection();
const handleScroll = React.useCallback(() => { const handleScroll = React.useCallback(() => {
if (window.pageYOffset !== 0) { if (window.pageYOffset !== 0) {
...@@ -43,8 +44,6 @@ const SearchBarMobile = ({ onChange, onSubmit, withShadow }: Props) => { ...@@ -43,8 +44,6 @@ const SearchBarMobile = ({ onChange, onSubmit, withShadow }: Props) => {
const bgColor = useColorModeValue('white', 'black'); const bgColor = useColorModeValue('white', 'black');
return ( return (
<ScrollDirectionContext.Consumer>
{ (scrollDirection) => (
<chakra.form <chakra.form
noValidate noValidate
onSubmit={ onSubmit } onSubmit={ onSubmit }
...@@ -76,8 +75,6 @@ const SearchBarMobile = ({ onChange, onSubmit, withShadow }: Props) => { ...@@ -76,8 +75,6 @@ const SearchBarMobile = ({ onChange, onSubmit, withShadow }: Props) => {
/> />
</InputGroup> </InputGroup>
</chakra.form> </chakra.form>
) }
</ScrollDirectionContext.Consumer>
); );
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment