diff --git a/package.json b/package.json index e42e9d1..19333bd 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,8 @@ "react-syntax-highlighter": "^15", "shiki-es": "^0.2", "use-merge-value": "^1", - "zustand": "^4" + "zustand": "^4", + "zustand-utils": "^1" }, "devDependencies": { "@commitlint/cli": "^17", diff --git a/src/components/StoreUpdater/index.tsx b/src/components/StoreUpdater/index.tsx index d0c33c3..5d6354a 100644 --- a/src/components/StoreUpdater/index.tsx +++ b/src/components/StoreUpdater/index.tsx @@ -10,7 +10,7 @@ import { } from 'dumi'; import isEqual from 'fast-deep-equal'; import React, { memo, useEffect } from 'react'; -import { SiteStore, useSiteStore } from '../../store/useSiteStore'; +import { SiteStore, useStoreApi } from '../../store/useSiteStore'; const isBrowser = typeof window !== 'undefined'; @@ -40,9 +40,10 @@ const useSyncState = ( value: SiteStore[T], updateMethod?: (key: T, value: SiteStore[T]) => void, ) => { + const storeApi = useStoreApi(); const updater = updateMethod ? updateMethod - : (key: T, value: SiteStore[T]) => useSiteStore.setState({ [key]: value }); + : (key: T, value: SiteStore[T]) => storeApi.setState({ [key]: value }); // 如果是 Node 环境,直接更新一次 store // 但是为了避免多次更新 store,所以加一个标记 @@ -70,6 +71,7 @@ export const StoreUpdater = memo(() => { const navData = useNavData(); const location = useLocation(); const locale = useLocale(); + const storeApi = useStoreApi(); useSyncState('siteData', siteData, () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -77,11 +79,11 @@ export const StoreUpdater = memo(() => { const { // eslint-disable-next-line @typescript-eslint/no-unused-vars siteData: { setLoading: _, ...prevData }, - } = useSiteStore.getState(); + } = storeApi.getState(); if (isEqual(data, prevData)) return; - useSiteStore.setState({ siteData }); + storeApi.setState({ siteData }); }); useSyncState('sidebar', sidebar); @@ -93,7 +95,7 @@ export const StoreUpdater = memo(() => { useSyncState('navData', navData, () => { const data = siteData.themeConfig.hideHomeNav ? navData : [homeNav, ...navData]; - useSiteStore.setState({ navData: data }); + storeApi.setState({ navData: data }); }); return null; diff --git a/src/layouts/DocLayout/index.tsx b/src/layouts/DocLayout/index.tsx index 5c8e885..87d7e79 100644 --- a/src/layouts/DocLayout/index.tsx +++ b/src/layouts/DocLayout/index.tsx @@ -1,7 +1,17 @@ import { extractStaticStyle } from 'antd-style'; -import { Helmet, useIntl, useLocation } from 'dumi'; +import { + Helmet, + useIntl, + useLocale, + useLocation, + useNavData, + useRouteMeta, + useSidebarData, + useSiteData, + useTabMeta, +} from 'dumi'; import isEqual from 'fast-deep-equal'; -import { PropsWithChildren, memo, useEffect, type FC } from 'react'; +import { PropsWithChildren, memo, useEffect, useMemo, type FC } from 'react'; import DumiSiteProvider from '../../components/DumiSiteProvider'; import { StoreUpdater } from '../../components/StoreUpdater'; @@ -9,7 +19,7 @@ import { StoreUpdater } from '../../components/StoreUpdater'; import Docs from '../../pages/Docs'; import Home from '../../pages/Home'; -import { isHeroPageSel, tokenSel, useSiteStore } from '../../store'; +import { Provider, createStore, isHeroPageSel, tokenSel, useSiteStore } from '../../store'; import { GlobalStyle } from './styles'; const DocLayout: FC = memo(() => { @@ -64,12 +74,29 @@ const ThemeProvider = ({ children }: PropsWithChildren) => { ); }; -export default () => ( - <> +const App = memo(({ initState }: any) => ( + createStore(initState)}> - -); + +)); + +export default () => { + const siteData = useSiteData(); + const sidebar = useSidebarData(); + const routeMeta = useRouteMeta(); + const tabMeta = useTabMeta(); + const navData = useNavData(); + const location = useLocation(); + const locale = useLocale(); + + const initState = useMemo( + () => ({ siteData, navData, locale, location, routeMeta, tabMeta, sidebar }), + [], + ); + + return ; +}; diff --git a/src/store/useSiteStore.ts b/src/store/useSiteStore.ts index 40cb018..c661441 100644 --- a/src/store/useSiteStore.ts +++ b/src/store/useSiteStore.ts @@ -12,7 +12,8 @@ import { PICKED_PKG_FIELDS } from 'dumi/dist/constants'; import type { Location } from 'history'; import { ComponentType } from 'react'; -import { create } from 'zustand'; +import { create, StoreApi } from 'zustand'; +import { createContext } from 'zustand-utils'; import { devtools } from 'zustand/middleware'; export type NavData = (INavItem & { children?: INavItem[] | undefined })[]; @@ -46,46 +47,8 @@ export interface SiteStore { locale: ILocale; } -const initialState: SiteStore = { - siteData: { - // @ts-ignore - setLoading: undefined, - loading: true, - pkg: {}, - components: {}, - demos: {}, - locales: [], - entryExports: {}, - // @ts-ignore - themeConfig: {}, - }, - sidebar: [], - navData: [], +export const createStore = (initState: SiteStore) => + create()(devtools(() => initState, { name: 'dumi-theme-antd-style' })); - location: { - pathname: '', - state: '', - search: '', - hash: '', - key: '', - }, - - routeMeta: { - toc: [], - texts: [], - tabs: undefined, - // @ts-ignore - frontmatter: {}, - }, - - locale: { id: 'zh-CN', name: '中文', suffix: '' }, -}; - -export const useSiteStore = create()( - devtools( - () => ({ - ...initialState, - }), - { name: 'dumi-theme-antd-style' }, - ), -); +const { useStore, useStoreApi, Provider } = createContext>(); +export { useStore as useSiteStore, Provider, useStoreApi };