mirror of
https://github.com/nocobase/nocobase
synced 2024-11-16 01:45:53 +00:00
perf(MenuEditor): optimize router context
This commit is contained in:
parent
d786145fc2
commit
023aa0ce4f
@ -8,7 +8,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, useEffect } from 'react';
|
import React, { FC, useEffect } from 'react';
|
||||||
import { Location, NavigateFunction, NavigateOptions, useLocation, useNavigate } from 'react-router-dom';
|
import {
|
||||||
|
Location,
|
||||||
|
NavigateFunction,
|
||||||
|
NavigateOptions,
|
||||||
|
PathMatch,
|
||||||
|
useLocation,
|
||||||
|
useMatch,
|
||||||
|
useNavigate,
|
||||||
|
useParams,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
|
||||||
const NavigateNoUpdateContext = React.createContext<NavigateFunction>(null);
|
const NavigateNoUpdateContext = React.createContext<NavigateFunction>(null);
|
||||||
NavigateNoUpdateContext.displayName = 'NavigateNoUpdateContext';
|
NavigateNoUpdateContext.displayName = 'NavigateNoUpdateContext';
|
||||||
@ -22,12 +31,36 @@ LocationSearchContext.displayName = 'LocationSearchContext';
|
|||||||
const IsAdminPageContext = React.createContext<boolean>(false);
|
const IsAdminPageContext = React.createContext<boolean>(false);
|
||||||
IsAdminPageContext.displayName = 'IsAdminPageContext';
|
IsAdminPageContext.displayName = 'IsAdminPageContext';
|
||||||
|
|
||||||
|
const CurrentPageUidContext = React.createContext<string>('');
|
||||||
|
CurrentPageUidContext.displayName = 'CurrentPageUidContext';
|
||||||
|
|
||||||
|
const MatchAdminContext = React.createContext<PathMatch<string> | null>(null);
|
||||||
|
MatchAdminContext.displayName = 'MatchAdminContext';
|
||||||
|
|
||||||
|
const MatchAdminNameContext = React.createContext<PathMatch<string> | null>(null);
|
||||||
|
MatchAdminNameContext.displayName = 'MatchAdminNameContext';
|
||||||
|
|
||||||
|
const MatchAdminProvider: FC = ({ children }) => {
|
||||||
|
const matchAdmin = useMatch('/admin');
|
||||||
|
return <MatchAdminContext.Provider value={matchAdmin}>{children}</MatchAdminContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const MatchAdminNameProvider: FC = ({ children }) => {
|
||||||
|
const matchAdminName = useMatch('/admin/:name');
|
||||||
|
return <MatchAdminNameContext.Provider value={matchAdminName}>{children}</MatchAdminNameContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
const IsAdminPageProvider: FC = ({ children }) => {
|
const IsAdminPageProvider: FC = ({ children }) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const isAdminPage = location.pathname.startsWith('/admin');
|
const isAdminPage = location.pathname.startsWith('/admin');
|
||||||
return <IsAdminPageContext.Provider value={isAdminPage}>{children}</IsAdminPageContext.Provider>;
|
return <IsAdminPageContext.Provider value={isAdminPage}>{children}</IsAdminPageContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CurrentPageUidProvider: FC = ({ children }) => {
|
||||||
|
const params = useParams<any>();
|
||||||
|
return <CurrentPageUidContext.Provider value={params.name}>{children}</CurrentPageUidContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the URL changes, components that use `useNavigate` will re-render.
|
* When the URL changes, components that use `useNavigate` will re-render.
|
||||||
* This provider provides a `navigateNoUpdate` method that can avoid re-rendering.
|
* This provider provides a `navigateNoUpdate` method that can avoid re-rendering.
|
||||||
@ -96,12 +129,30 @@ export const useIsAdminPage = () => {
|
|||||||
return React.useContext(IsAdminPageContext);
|
return React.useContext(IsAdminPageContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useCurrentPageUid = () => {
|
||||||
|
return React.useContext(CurrentPageUidContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMatchAdmin = () => {
|
||||||
|
return React.useContext(MatchAdminContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMatchAdminName = () => {
|
||||||
|
return React.useContext(MatchAdminNameContext);
|
||||||
|
};
|
||||||
|
|
||||||
export const CustomRouterContextProvider: FC = ({ children }) => {
|
export const CustomRouterContextProvider: FC = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<NavigateNoUpdateProvider>
|
<NavigateNoUpdateProvider>
|
||||||
<LocationNoUpdateProvider>
|
<LocationNoUpdateProvider>
|
||||||
<IsAdminPageProvider>
|
<IsAdminPageProvider>
|
||||||
<LocationSearchProvider>{children}</LocationSearchProvider>
|
<LocationSearchProvider>
|
||||||
|
<CurrentPageUidProvider>
|
||||||
|
<MatchAdminProvider>
|
||||||
|
<MatchAdminNameProvider>{children}</MatchAdminNameProvider>
|
||||||
|
</MatchAdminProvider>
|
||||||
|
</CurrentPageUidProvider>
|
||||||
|
</LocationSearchProvider>
|
||||||
</IsAdminPageProvider>
|
</IsAdminPageProvider>
|
||||||
</LocationNoUpdateProvider>
|
</LocationNoUpdateProvider>
|
||||||
</NavigateNoUpdateProvider>
|
</NavigateNoUpdateProvider>
|
||||||
|
@ -12,7 +12,7 @@ import { useSessionStorageState } from 'ahooks';
|
|||||||
import { App, ConfigProvider, Divider, Layout } from 'antd';
|
import { App, ConfigProvider, Divider, Layout } from 'antd';
|
||||||
import { createGlobalStyle } from 'antd-style';
|
import { createGlobalStyle } from 'antd-style';
|
||||||
import React, { FC, createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { FC, createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Link, Outlet, useMatch, useParams } from 'react-router-dom';
|
import { Link, Outlet, useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
ACLRolesCheckProvider,
|
ACLRolesCheckProvider,
|
||||||
CurrentAppInfoProvider,
|
CurrentAppInfoProvider,
|
||||||
@ -33,7 +33,13 @@ import {
|
|||||||
useSystemSettings,
|
useSystemSettings,
|
||||||
useToken,
|
useToken,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { useLocationNoUpdate, useNavigateNoUpdate } from '../../../application/CustomRouterContextProvider';
|
import {
|
||||||
|
useCurrentPageUid,
|
||||||
|
useLocationNoUpdate,
|
||||||
|
useMatchAdmin,
|
||||||
|
useMatchAdminName,
|
||||||
|
useNavigateNoUpdate,
|
||||||
|
} from '../../../application/CustomRouterContextProvider';
|
||||||
import { Plugin } from '../../../application/Plugin';
|
import { Plugin } from '../../../application/Plugin';
|
||||||
import { useAppSpin } from '../../../application/hooks/useAppSpin';
|
import { useAppSpin } from '../../../application/hooks/useAppSpin';
|
||||||
import { useMenuTranslation } from '../../../schema-component/antd/menu/locale';
|
import { useMenuTranslation } from '../../../schema-component/antd/menu/locale';
|
||||||
@ -82,12 +88,11 @@ const MenuEditor = (props) => {
|
|||||||
const { setTitle: _setTitle } = useDocumentTitle();
|
const { setTitle: _setTitle } = useDocumentTitle();
|
||||||
const setTitle = useCallback((title) => _setTitle(t(title)), []);
|
const setTitle = useCallback((title) => _setTitle(t(title)), []);
|
||||||
const navigate = useNavigateNoUpdate();
|
const navigate = useNavigateNoUpdate();
|
||||||
const params = useParams<any>();
|
|
||||||
const location = useLocationNoUpdate();
|
const location = useLocationNoUpdate();
|
||||||
const isMatchAdmin = useMatch('/admin');
|
const isMatchAdmin = useMatchAdmin();
|
||||||
const isMatchAdminName = useMatch('/admin/:name');
|
const isMatchAdminName = useMatchAdminName();
|
||||||
const defaultSelectedUid = params.name;
|
const currentPageUid = useCurrentPageUid();
|
||||||
const isDynamicPage = !!defaultSelectedUid;
|
const isDynamicPage = !!currentPageUid;
|
||||||
const { sideMenuRef } = props;
|
const { sideMenuRef } = props;
|
||||||
const ctx = useACLRoleContext();
|
const ctx = useACLRoleContext();
|
||||||
const [current, setCurrent] = useState(null);
|
const [current, setCurrent] = useState(null);
|
||||||
@ -126,7 +131,7 @@ const MenuEditor = (props) => {
|
|||||||
if (!isMatchAdminName || !isDynamicPage) return;
|
if (!isMatchAdminName || !isDynamicPage) return;
|
||||||
|
|
||||||
// url 为 `admin/xxx` 的情况
|
// url 为 `admin/xxx` 的情况
|
||||||
const s = findByUid(schema, defaultSelectedUid);
|
const s = findByUid(schema, currentPageUid);
|
||||||
if (s) {
|
if (s) {
|
||||||
setTitle(s.title);
|
setTitle(s.title);
|
||||||
} else {
|
} else {
|
||||||
@ -147,7 +152,9 @@ const MenuEditor = (props) => {
|
|||||||
if (sideMenuRef.current) {
|
if (sideMenuRef.current) {
|
||||||
const pageType =
|
const pageType =
|
||||||
properties &&
|
properties &&
|
||||||
Object.values(properties).find((item) => item['x-uid'] === params.name && item['x-component'] === 'Menu.Item');
|
Object.values(properties).find(
|
||||||
|
(item) => item['x-uid'] === currentPageUid && item['x-component'] === 'Menu.Item',
|
||||||
|
);
|
||||||
const isSettingPage = location?.pathname.includes('/settings');
|
const isSettingPage = location?.pathname.includes('/settings');
|
||||||
if (pageType || isSettingPage) {
|
if (pageType || isSettingPage) {
|
||||||
sideMenuRef.current.style.display = 'none';
|
sideMenuRef.current.style.display = 'none';
|
||||||
@ -155,7 +162,7 @@ const MenuEditor = (props) => {
|
|||||||
sideMenuRef.current.style.display = 'block';
|
sideMenuRef.current.style.display = 'block';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [data?.data, params.name, sideMenuRef, location?.pathname]);
|
}, [data?.data, currentPageUid, sideMenuRef, location?.pathname]);
|
||||||
|
|
||||||
const schema = useMemo(() => {
|
const schema = useMemo(() => {
|
||||||
const s = filterByACL(data?.data, ctx);
|
const s = filterByACL(data?.data, ctx);
|
||||||
@ -167,12 +174,12 @@ const MenuEditor = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isMatchAdminName) {
|
if (isMatchAdminName) {
|
||||||
const s = findByUid(schema, defaultSelectedUid);
|
const s = findByUid(schema, currentPageUid);
|
||||||
if (s) {
|
if (s) {
|
||||||
setTitle(s.title);
|
setTitle(s.title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [defaultSelectedUid, isMatchAdmin, isMatchAdminName, schema, setTitle]);
|
}, [currentPageUid, isMatchAdmin, isMatchAdminName, schema, setTitle]);
|
||||||
|
|
||||||
useRequest(
|
useRequest(
|
||||||
{
|
{
|
||||||
@ -213,14 +220,14 @@ const MenuEditor = (props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const scope = useMemo(() => {
|
const scope = useMemo(() => {
|
||||||
return { useMenuProps, onSelect, sideMenuRef, defaultSelectedUid };
|
return { useMenuProps, onSelect, sideMenuRef, defaultSelectedUid: currentPageUid };
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return render();
|
return render();
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<SchemaIdContext.Provider value={defaultSelectedUid}>
|
<SchemaIdContext.Provider value={currentPageUid}>
|
||||||
<SchemaComponent distributed scope={scope} schema={schema} />
|
<SchemaComponent distributed scope={scope} schema={schema} />
|
||||||
</SchemaIdContext.Provider>
|
</SchemaIdContext.Provider>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user