remove ScrollArea as it causes performance issues on chrome (#1087)

This commit is contained in:
Athou
2023-06-24 23:00:25 +02:00
parent 53b06f41f3
commit bdcfbc22bf
6 changed files with 26 additions and 57 deletions

View File

@@ -94,7 +94,6 @@ export const Constants = {
isBottomVisible: (div: HTMLElement) => div.getBoundingClientRect().bottom <= window.innerHeight, isBottomVisible: (div: HTMLElement) => div.getBoundingClientRect().bottom <= window.innerHeight,
}, },
dom: { dom: {
mainScrollAreaId: "main-scroll-area-id",
entryId: (entry: Entry) => `entry-id-${entry.id}`, entryId: (entry: Entry) => `entry-id-${entry.id}`,
}, },
browserExtensionUrl: "https://github.com/Athou/commafeed-browser-extension", browserExtensionUrl: "https://github.com/Athou/commafeed-browser-extension",

View File

@@ -204,18 +204,14 @@ export const selectEntry = createAsyncThunk<
} }
}) })
const scrollToEntry = (entryElement: HTMLElement, scrollSpeed: number | undefined, onScrollEnded: () => void) => { const scrollToEntry = (entryElement: HTMLElement, scrollSpeed: number | undefined, onScrollEnded: () => void) => {
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId) scrollToWithCallback({
if (scrollArea) { options: {
scrollToWithCallback({ // add a small gap between the top of the content and the top of the page
element: scrollArea, top: entryElement.offsetTop - Constants.layout.headerHeight - 3,
options: { behavior: scrollSpeed && scrollSpeed > 0 ? "smooth" : "auto",
// add a small gap between the top of the content and the top of the page },
top: entryElement.offsetTop - 3, onScrollEnded,
behavior: scrollSpeed && scrollSpeed > 0 ? "smooth" : "auto", })
},
onScrollEnded,
})
}
} }
export const selectPreviousEntry = createAsyncThunk< export const selectPreviousEntry = createAsyncThunk<

View File

@@ -26,30 +26,22 @@ export const calculatePlaceholderSize = ({ width, height, maxWidth }: { width?:
return { width: placeholderWidth, height: placeholderHeight } return { width: placeholderWidth, height: placeholderHeight }
} }
export const scrollToWithCallback = ({ export const scrollToWithCallback = ({ options, onScrollEnded }: { options: ScrollToOptions; onScrollEnded: () => void }) => {
element,
options,
onScrollEnded,
}: {
element: HTMLElement
options: ScrollToOptions
onScrollEnded: () => void
}) => {
const offset = (options.top ?? 0).toFixed() const offset = (options.top ?? 0).toFixed()
const onScroll = () => { const onScroll = () => {
if (element.offsetTop.toFixed() === offset) { if (window.scrollY.toFixed() === offset) {
element.removeEventListener("scroll", onScroll) window.removeEventListener("scroll", onScroll)
onScrollEnded() onScrollEnded()
} }
} }
element.addEventListener("scroll", onScroll) window.addEventListener("scroll", onScroll)
// scrollTo does not trigger if there's nothing to do, trigger it manually // scrollTo does not trigger if there's nothing to do, trigger it manually
onScroll() onScroll()
element.scrollTo(options) window.scrollTo(options)
} }
export const truncate = (str: string, n: number) => (str.length > n ? `${str.slice(0, n - 1)}\u2026` : str) export const truncate = (str: string, n: number) => (str.length > n ? `${str.slice(0, n - 1)}\u2026` : str)

View File

@@ -74,8 +74,6 @@ export function FeedEntries() {
const swipedRight = (entry: ExpendableEntry) => dispatch(markEntry({ entry, read: !entry.read })) const swipedRight = (entry: ExpendableEntry) => dispatch(markEntry({ entry, read: !entry.read }))
useEffect(() => { useEffect(() => {
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId)
const listener = () => { const listener = () => {
if (viewMode !== "expanded") return if (viewMode !== "expanded") return
if (scrollingToEntry) return if (scrollingToEntry) return
@@ -100,8 +98,8 @@ export function FeedEntries() {
} }
} }
const throttledListener = throttle(100, listener) const throttledListener = throttle(100, listener)
scrollArea?.addEventListener("scroll", throttledListener) window.addEventListener("scroll", throttledListener)
return () => scrollArea?.removeEventListener("scroll", throttledListener) return () => window.removeEventListener("scroll", throttledListener)
}, [dispatch, entries, viewMode, scrollMarks, scrollingToEntry]) }, [dispatch, entries, viewMode, scrollMarks, scrollingToEntry])
useMousetrap("r", () => dispatch(reloadEntries())) useMousetrap("r", () => dispatch(reloadEntries()))
@@ -154,9 +152,8 @@ export function FeedEntries() {
}) })
) )
} else { } else {
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId) window.scrollTo({
scrollArea?.scrollTo({ top: window.scrollY + document.documentElement.clientHeight * 0.8,
top: scrollArea.scrollTop + scrollArea.clientHeight * 0.8,
behavior: "smooth", behavior: "smooth",
}) })
} }
@@ -193,9 +190,8 @@ export function FeedEntries() {
}) })
) )
} else { } else {
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId) window.scrollTo({
scrollArea?.scrollTo({ top: window.scrollY - document.documentElement.clientHeight * 0.8,
top: scrollArea.scrollTop - scrollArea.clientHeight * 0.8,
behavior: "smooth", behavior: "smooth",
}) })
} }
@@ -267,8 +263,6 @@ export function FeedEntries() {
loadMore={() => dispatch(loadMoreEntries())} loadMore={() => dispatch(loadMoreEntries())}
hasMore={hasMore} hasMore={hasMore}
loader={<Loader key={0} />} loader={<Loader key={0} />}
useWindow={false}
getScrollParent={() => document.getElementById(Constants.dom.mainScrollAreaId)}
> >
{entries.map(entry => ( {entries.map(entry => (
<div <div

View File

@@ -1,6 +1,5 @@
import { Trans } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { createStyles, Group } from "@mantine/core" import { createStyles, Group } from "@mantine/core"
import { Constants } from "app/constants"
import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries" import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries"
import { redirectToFeed } from "app/slices/redirect" import { redirectToFeed } from "app/slices/redirect"
import { useAppDispatch, useAppSelector } from "app/store" import { useAppDispatch, useAppSelector } from "app/store"
@@ -117,13 +116,11 @@ export function useFeedEntryContextMenu(entry: Entry) {
// close context menu on scroll // close context menu on scroll
useEffect(() => { useEffect(() => {
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId)
const listener = () => contextMenu.hideAll() const listener = () => contextMenu.hideAll()
const throttledListener = throttle(100, listener) const throttledListener = throttle(100, listener)
scrollArea?.addEventListener("scroll", throttledListener) window.addEventListener("scroll", throttledListener)
return () => scrollArea?.removeEventListener("scroll", throttledListener) return () => window.removeEventListener("scroll", throttledListener)
}, [contextMenu]) }, [contextMenu])
return { onContextMenu } return { onContextMenu }

View File

@@ -13,7 +13,6 @@ import {
Title, Title,
useMantineTheme, useMantineTheme,
} from "@mantine/core" } from "@mantine/core"
import { useViewportSize } from "@mantine/hooks"
import { Constants } from "app/constants" import { Constants } from "app/constants"
import { redirectToAdd, redirectToRootCategory } from "app/slices/redirect" import { redirectToAdd, redirectToRootCategory } from "app/slices/redirect"
import { reloadTree, setMobileMenuOpen, setSidebarWidth } from "app/slices/tree" import { reloadTree, setMobileMenuOpen, setSidebarWidth } from "app/slices/tree"
@@ -91,7 +90,6 @@ function LogoAndTitle() {
export default function Layout(props: LayoutProps) { export default function Layout(props: LayoutProps) {
const { classes } = useStyles(props) const { classes } = useStyles(props)
const theme = useMantineTheme() const theme = useMantineTheme()
const viewport = useViewportSize()
const { loading } = useAppLoading() const { loading } = useAppLoading()
const mobile = useMobile() const mobile = useMobile()
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen) const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
@@ -197,18 +195,11 @@ export default function Layout(props: LayoutProps) {
</Header> </Header>
} }
> >
<ScrollArea <Box id="content" className={classes.mainContent}>
sx={{ height: viewport.height - Constants.layout.headerHeight }} <Suspense fallback={<Loader />}>
viewportRef={ref => { <Outlet />
if (ref) ref.id = Constants.dom.mainScrollAreaId </Suspense>
}} </Box>
>
<Box id="content" className={classes.mainContent}>
<Suspense fallback={<Loader />}>
<Outlet />
</Suspense>
</Box>
</ScrollArea>
</AppShell> </AppShell>
) )
} }