From a2d506b758ab56b44aade0bd45ed8c65b39404f8 Mon Sep 17 00:00:00 2001 From: Marvin Heilemann Date: Wed, 4 Mar 2020 19:12:32 +0100 Subject: [PATCH] feat: update scroll to top with better logic --- src/components/ScrollToTop.jsx | 8 ++--- src/hooks/use-scroll-position.js | 50 -------------------------------- src/hooks/use-window.js | 35 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 54 deletions(-) delete mode 100644 src/hooks/use-scroll-position.js create mode 100644 src/hooks/use-window.js diff --git a/src/components/ScrollToTop.jsx b/src/components/ScrollToTop.jsx index 00e7e15..a694be0 100644 --- a/src/components/ScrollToTop.jsx +++ b/src/components/ScrollToTop.jsx @@ -2,13 +2,13 @@ import React, { useState } from 'react' import { animateScroll } from 'react-scroll' import Icon from './Icon' -import { useScrollPosition } from '../hooks/use-scroll-position' +import { useScroll } from '../hooks/use-window' const ScrollToTop = () => { const [visible, setVisibility] = useState(false) - useScrollPosition(({ currPos }) => { - if (currPos.y < -600) { + useScroll(({ top }) => { + if (top > 600) { setVisibility(true) } else { setVisibility(false) @@ -31,7 +31,7 @@ const ScrollToTop = () => { tabIndex="0" role="button" > - + ) } diff --git a/src/hooks/use-scroll-position.js b/src/hooks/use-scroll-position.js deleted file mode 100644 index 28f62f7..0000000 --- a/src/hooks/use-scroll-position.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Scroll position hook for react. - * - * @author n8tb1t - * @see https://github.com/n8tb1t/use-scroll-position - */ - -import { useRef, useLayoutEffect } from 'react' - -const isBrowser = typeof window !== `undefined` - -function getScrollPosition({ element, useWindow }) { - if (!isBrowser) return { x: 0, y: 0 } - - const target = element ? element.current : document.body - const position = target.getBoundingClientRect() - - return useWindow - ? { x: window.scrollX, y: window.scrollY } - : { x: position.left, y: position.top } -} - -export function useScrollPosition(effect, deps, element, useWindow, wait = 200) { - const position = useRef(getScrollPosition({ useWindow })) - - let throttleTimeout = null - - const callBack = () => { - const currPos = getScrollPosition({ element, useWindow }) - effect({ prevPos: position.current, currPos }) - position.current = currPos - throttleTimeout = null - } - - useLayoutEffect(() => { - const handleScroll = () => { - if (wait) { - if (throttleTimeout === null) { - throttleTimeout = setTimeout(callBack, wait) - } - } else { - callBack() - } - } - - window.addEventListener('scroll', handleScroll) - - return () => window.removeEventListener('scroll', handleScroll) - }, deps) -} diff --git a/src/hooks/use-window.js b/src/hooks/use-window.js new file mode 100644 index 0000000..74f23ee --- /dev/null +++ b/src/hooks/use-window.js @@ -0,0 +1,35 @@ +import { useLayoutEffect } from 'react' +import debounce from 'lodash/debounce' + +const isBrowser = typeof window !== `undefined` + +function getBoundingRect() { + if (!isBrowser) return { left: 0, top: 0, width: 0, height: 0 } + + return { + left: window.scrollX, + top: window.scrollY, + width: window.innerWidth, + height: window.innerHeight, + } +} + +function handler(event, effect, wait) { + const handleScroll = debounce(() => { + effect(getBoundingRect()) + }, wait) + + window.addEventListener(event, handleScroll) + + return () => window.removeEventListener(event, handleScroll) +} + +function useScroll(effect, wait = 250) { + useLayoutEffect(() => handler('scroll', effect, wait)) +} + +function useResize(effect, wait = 100) { + useLayoutEffect(() => handler('resize', effect, wait)) +} + +export { getBoundingRect, useScroll, useResize }