import { useDebounceEffect } from 'ahooks'; import { useLocale, useLocation, useNavData, useSidebarData, useSiteData, useTabMeta } from 'dumi'; import isEqual from 'fast-deep-equal'; import React, { memo, useEffect } from 'react'; import { SiteStore, useStoreApi } from '../../store/useSiteStore'; import { useRouteMeta } from './useRouteMeta'; const isBrowser = typeof window !== 'undefined'; const SSRInit: Record = {}; const useReact18xUpdater = (effect: React.EffectCallback, deps?: React.DependencyList) => { useEffect(() => { (React as any).startTransition(() => { effect(); }); }, deps); }; const useLegacyUpdater = (effect: React.EffectCallback, deps?: React.DependencyList) => { useDebounceEffect( () => { effect(); }, deps, { wait: 32, maxWait: 96 }, ); }; const useUpdater = typeof (React as any).startTransition === 'function' ? useReact18xUpdater : useLegacyUpdater; const useSyncState = ( key: T, value: SiteStore[T], updateMethod?: (key: T, value: SiteStore[T]) => void, ) => { const storeApi = useStoreApi(); const updater = updateMethod ? updateMethod : (key: T, value: SiteStore[T]) => storeApi.setState({ [key]: value }); // 如果是 Node 环境,直接更新一次 store // 但是为了避免多次更新 store,所以加一个标记 if (!isBrowser && !SSRInit[key]) { updater(key, value); SSRInit[key] = true; } useUpdater(() => { updater(key, value); }, [value]); }; const displayLangHomeNavMap: Record = { 'zh-CN': '首页', 'en-US': 'Home', }; const getHomeNav = (id: string) => ({ title: displayLangHomeNavMap[id], link: '/', activePath: '/', }); export const StoreUpdater = memo(() => { const siteData = useSiteData(); const sidebar = useSidebarData(); const tabMeta = useTabMeta(); const navData = useNavData(); const location = useLocation(); const locale = useLocale(); const storeApi = useStoreApi(); useRouteMeta(); useSyncState('siteData', siteData, () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { setLoading, ...data } = siteData; const { // eslint-disable-next-line @typescript-eslint/no-unused-vars siteData: { setLoading: _, ...prevData }, } = storeApi.getState(); if (isEqual(data, prevData)) return; storeApi.setState({ siteData }); }); useSyncState('sidebar', sidebar); useSyncState('location', location); useSyncState('tabMeta', tabMeta); useSyncState('locale', locale); useSyncState('navData', navData, () => { const data = siteData.themeConfig.hideHomeNav ? navData : [getHomeNav(locale.id), ...navData]; storeApi.setState({ navData: data }); }); return null; });