From 3bb1b2f8c1895349d6685cb73b5ef7aa213a7795 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Wed, 19 Jun 2024 22:55:22 +0200 Subject: [PATCH] perf(use-theme): refactor for performance, fix initial theme load after refresh --- src/app.tsx | 8 +++++ src/hooks/use-initial-theme.ts | 37 +++++++++++++++++++ src/hooks/use-theme.ts | 65 +++++++++++++++++----------------- 3 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 src/hooks/use-initial-theme.ts diff --git a/src/app.tsx b/src/app.tsx index 8b1ea752..d735a1a1 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,3 +1,4 @@ +import { useEffect } from 'react'; import { Outlet, Route, Routes, useLocation, useParams } from 'react-router-dom'; import { isAllView, isSubscriptionsView } from './lib/utils/view-utils'; import useIsMobile from './hooks/use-is-mobile'; @@ -16,6 +17,7 @@ import SubplebbitStats from './components/subplebbit-stats'; import TopBar from './components/topbar'; import { timeFilterNames } from './hooks/use-time-filter'; import useTheme from './hooks/use-theme'; +import useInitialTheme from './hooks/use-initial-theme'; const BoardLayout = () => { const { accountCommentIndex, subplebbitAddress, timeFilterName } = useParams(); @@ -68,6 +70,12 @@ const GlobalLayout = () => { }; const App = () => { + const initialTheme = useInitialTheme(); + + useEffect(() => { + document.body.classList.add(initialTheme); + }, [initialTheme]); + return (
diff --git a/src/hooks/use-initial-theme.ts b/src/hooks/use-initial-theme.ts new file mode 100644 index 00000000..d445f83c --- /dev/null +++ b/src/hooks/use-initial-theme.ts @@ -0,0 +1,37 @@ +import { useLocation, useParams } from 'react-router-dom'; +import useThemeStore from '../stores/use-theme-store'; +import useDefaultSubplebbits from './use-default-subplebbits'; +import { isAllView, isHomeView, isNotFoundView, isSubscriptionsView } from '../lib/utils/view-utils'; +import { nsfwTags } from '../views/home/home'; + +const useInitialTheme = () => { + const location = useLocation(); + const { subplebbitAddress } = useParams<{ subplebbitAddress: string }>(); + const getTheme = useThemeStore((state) => state.getTheme); + const subplebbits = useDefaultSubplebbits(); + const params = useParams(); + const isInHomeView = isHomeView(location.pathname); + const isInNotFoundView = isNotFoundView(location.pathname, params); + const isInAllView = isAllView(location.pathname, params); + const isInSubscriptionsView = isSubscriptionsView(location.pathname, params); + + if (isInAllView || isInSubscriptionsView) { + const userTheme = getTheme(isInAllView ? 'all' : 'subscriptions'); + return userTheme || 'yotsuba-b'; + } else if (isInHomeView || isInNotFoundView) { + return 'yotsuba'; + } else if (subplebbitAddress) { + const userTheme = getTheme(subplebbitAddress); + if (userTheme) { + return userTheme; + } + const subplebbit = subplebbits.find((s) => s.address === subplebbitAddress); + if (subplebbit && subplebbit.tags && subplebbit.tags.some((tag) => nsfwTags.includes(tag))) { + return 'yotsuba'; + } + return 'yotsuba-b'; + } + return 'yotsuba'; +}; + +export default useInitialTheme; diff --git a/src/hooks/use-theme.ts b/src/hooks/use-theme.ts index e5dd466d..ccfc242e 100644 --- a/src/hooks/use-theme.ts +++ b/src/hooks/use-theme.ts @@ -1,50 +1,49 @@ -import { useState, useMemo } from 'react'; +import { useState, useEffect } from 'react'; import { useLocation, useParams } from 'react-router-dom'; +import { isAllView, isSubscriptionsView } from '../lib/utils/view-utils'; import useThemeStore from '../stores/use-theme-store'; -import useDefaultSubplebbits from './use-default-subplebbits'; -import { isAllView, isHomeView, isNotFoundView, isSubscriptionsView } from '../lib/utils/view-utils'; -import { nsfwTags } from '../views/home/home'; +import determineInitialTheme from './use-initial-theme'; const useTheme = (): [string, (theme: string) => void] => { const location = useLocation(); - const { subplebbitAddress } = useParams<{ subplebbitAddress: string }>(); - const getTheme = useThemeStore((state) => state.getTheme); - const setThemeStore = useThemeStore((state) => state.setTheme); - const subplebbits = useDefaultSubplebbits(); const params = useParams(); - const isInHomeView = isHomeView(location.pathname); - const isInNotFoundView = isNotFoundView(location.pathname, params); - const isInAllView = isAllView(location.pathname, params); - const isInSubscriptionsView = isSubscriptionsView(location.pathname, params); + const setThemeStore = useThemeStore((state) => state.setTheme); + const loadThemes = useThemeStore((state) => state.loadThemes); - const initialTheme = useMemo(() => { - if (isInAllView || isInSubscriptionsView) { - const userTheme = getTheme(isInAllView ? 'all' : 'subscriptions'); - return userTheme || 'yotsuba-b'; - } else if (isInHomeView || isInNotFoundView) { - return 'yotsuba'; - } else if (subplebbitAddress) { - const userTheme = getTheme(subplebbitAddress); - if (userTheme) { - return userTheme; - } - const subplebbit = subplebbits.find((s) => s.address === subplebbitAddress); - if (subplebbit && subplebbit.tags && subplebbit.tags.some((tag) => nsfwTags.includes(tag))) { - return 'yotsuba'; - } - return 'yotsuba-b'; - } - return 'yotsuba'; - }, [subplebbitAddress, subplebbits, getTheme, isInAllView, isInHomeView, isInNotFoundView, isInSubscriptionsView]); + const [themesLoaded, setThemesLoaded] = useState(false); + + useEffect(() => { + const load = async () => { + await loadThemes(); + setThemesLoaded(true); + }; + load(); + }, [loadThemes]); + + const initialTheme = determineInitialTheme(); const [theme, setLocalTheme] = useState(initialTheme); - useMemo(() => { - document.body.classList.remove('yotsuba', 'yotsuba-b', 'futaba', 'burichan', 'tomorrow', 'photon'); + useEffect(() => { document.body.classList.add(initialTheme); + return () => { + document.body.classList.remove(initialTheme); + }; }, [initialTheme]); + useEffect(() => { + if (themesLoaded) { + document.body.classList.remove('yotsuba', 'yotsuba-b', 'futaba', 'burichan', 'tomorrow', 'photon'); + document.body.classList.add(initialTheme); + setLocalTheme(initialTheme); + } + }, [initialTheme, themesLoaded]); + const setSubplebbitTheme = (newTheme: string) => { + const subplebbitAddress = params?.subplebbitAddress; + const isInAllView = isAllView(location.pathname, params); + const isInSubscriptionsView = isSubscriptionsView(location.pathname, params); + if (subplebbitAddress) { setThemeStore(subplebbitAddress, newTheme); } else if (isInAllView) {