From f1ceeba2fd320dcad316a0a4758a76407fbd98a0 Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Tue, 4 Jul 2023 08:59:31 +0800 Subject: [PATCH] Refactor category scroll handlers (#1069) * state enum * combine some useEffects * combine all useeffects * formatting --- interface/app/$libraryId/Layout/index.tsx | 6 +- .../app/$libraryId/overview/Categories.tsx | 125 +++++++++--------- 2 files changed, 67 insertions(+), 64 deletions(-) diff --git a/interface/app/$libraryId/Layout/index.tsx b/interface/app/$libraryId/Layout/index.tsx index 8af9998cf..98cd7d890 100644 --- a/interface/app/$libraryId/Layout/index.tsx +++ b/interface/app/$libraryId/Layout/index.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import { Suspense, useRef } from 'react'; +import { Suspense, useMemo, useRef } from 'react'; import { Navigate, Outlet } from 'react-router-dom'; import { ClientContextProvider, @@ -31,6 +31,8 @@ const Layout = () => { usePlausiblePageViewMonitor({ currentPath: rawPath }); + const ctxValue = useMemo(() => ({ ref: layoutRef }), [layoutRef]); + if (library === null && libraries.data) { const firstLibrary = libraries.data[0]; @@ -39,7 +41,7 @@ const Layout = () => { } return ( - +
{ - const layout = useLayoutContext(); const isDark = useIsDark(); const ref = useRef(null); const { events } = useDraggable(ref as React.MutableRefObject); + const { scroll, mouseState } = useMouseHandlers({ ref }); + const categories = useLibraryQuery(['categories.list']); - const [scroll, setScroll] = useState(0); const [lastCategoryVisible, setLastCategoryVisible] = useState(false); - const [mousedown, setMousedown] = useState(false); - const [dragging, setDragging] = useState(false); const handleArrowOnClick = (direction: 'right' | 'left') => { const element = ref.current; @@ -58,62 +56,6 @@ export const Categories = (props: { selected: Category; onSelectedChanged(c: Cat index === CategoryList.length - 1 && setLastCategoryVisible((prev) => !prev); }; - useEffect(() => { - const element = ref.current; - if (!element) return; - - const handleWheel = (event: WheelEvent) => { - event.preventDefault(); - const { deltaX, deltaY } = event; - const scrollAmount = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY; - element.scrollTo({ left: element.scrollLeft + scrollAmount }); - }; - - element.addEventListener('wheel', handleWheel); - return () => element.removeEventListener('wheel', handleWheel); - }, []); - - useEffect(() => { - const element = ref.current; - if (!element) return; - - const onScroll = () => { - setScroll(element.scrollLeft); - if (mousedown && !dragging) { - setDragging(true); - if (layout.ref.current) { - layout.ref.current.style.cursor = 'grabbing'; - } - } - }; - - element.addEventListener('scroll', onScroll); - return () => element.removeEventListener('scroll', onScroll); - }, [mousedown, dragging, layout.ref]); - - useEffect(() => { - const element = ref.current; - if (!element) return; - - const onMouseDown = () => setMousedown(true); - - element.addEventListener('mousedown', onMouseDown); - return () => element.removeEventListener('mousedown', onMouseDown); - }, []); - - useEffect(() => { - const onMouseUp = () => { - setMousedown(false); - setDragging(false); - if (layout.ref.current) { - layout.ref.current.style.cursor = ''; - } - }; - - window.addEventListener('mouseup', onMouseUp); - return () => window.removeEventListener('mouseup', onMouseUp); - }, [layout.ref]); - return (
); }; + +const useMouseHandlers = ({ ref }: { ref: RefObject }) => { + const layout = useLayoutContext(); + + const [scroll, setScroll] = useState(0); + + type MouseState = 'idle' | 'mousedown' | 'dragging'; + const [mouseState, setMouseState] = useState('idle'); + + useEffect(() => { + const element = ref.current; + if (!element) return; + + const onScroll = () => { + setScroll(element.scrollLeft); + + setMouseState((s) => { + if (s !== 'mousedown') return s; + + if (layout.ref.current) layout.ref.current.style.cursor = 'grabbing'; + + return 'dragging'; + }); + }; + const onWheel = (event: WheelEvent) => { + event.preventDefault(); + const { deltaX, deltaY } = event; + const scrollAmount = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY; + element.scrollTo({ left: element.scrollLeft + scrollAmount }); + }; + const onMouseDown = () => setMouseState('mousedown'); + + const onMouseUp = () => { + setMouseState('idle'); + if (layout.ref.current) { + layout.ref.current.style.cursor = ''; + } + }; + + element.addEventListener('scroll', onScroll); + element.addEventListener('wheel', onWheel); + element.addEventListener('mousedown', onMouseDown); + + window.addEventListener('mouseup', onMouseUp); + + return () => { + element.removeEventListener('scroll', onScroll); + element.removeEventListener('wheel', onWheel); + element.removeEventListener('mousedown', onMouseDown); + + window.removeEventListener('mouseup', onMouseUp); + }; + }, [ref, layout.ref]); + + return { scroll, mouseState }; +};