mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 23:26:38 +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 { 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);
|
||||
NavigateNoUpdateContext.displayName = 'NavigateNoUpdateContext';
|
||||
@ -22,12 +31,36 @@ LocationSearchContext.displayName = 'LocationSearchContext';
|
||||
const IsAdminPageContext = React.createContext<boolean>(false);
|
||||
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 location = useLocation();
|
||||
const isAdminPage = location.pathname.startsWith('/admin');
|
||||
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.
|
||||
* This provider provides a `navigateNoUpdate` method that can avoid re-rendering.
|
||||
@ -96,12 +129,30 @@ export const useIsAdminPage = () => {
|
||||
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 }) => {
|
||||
return (
|
||||
<NavigateNoUpdateProvider>
|
||||
<LocationNoUpdateProvider>
|
||||
<IsAdminPageProvider>
|
||||
<LocationSearchProvider>{children}</LocationSearchProvider>
|
||||
<LocationSearchProvider>
|
||||
<CurrentPageUidProvider>
|
||||
<MatchAdminProvider>
|
||||
<MatchAdminNameProvider>{children}</MatchAdminNameProvider>
|
||||
</MatchAdminProvider>
|
||||
</CurrentPageUidProvider>
|
||||
</LocationSearchProvider>
|
||||
</IsAdminPageProvider>
|
||||
</LocationNoUpdateProvider>
|
||||
</NavigateNoUpdateProvider>
|
||||
|
@ -12,7 +12,7 @@ import { useSessionStorageState } from 'ahooks';
|
||||
import { App, ConfigProvider, Divider, Layout } from 'antd';
|
||||
import { createGlobalStyle } from 'antd-style';
|
||||
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 {
|
||||
ACLRolesCheckProvider,
|
||||
CurrentAppInfoProvider,
|
||||
@ -33,7 +33,13 @@ import {
|
||||
useSystemSettings,
|
||||
useToken,
|
||||
} from '../../../';
|
||||
import { useLocationNoUpdate, useNavigateNoUpdate } from '../../../application/CustomRouterContextProvider';
|
||||
import {
|
||||
useCurrentPageUid,
|
||||
useLocationNoUpdate,
|
||||
useMatchAdmin,
|
||||
useMatchAdminName,
|
||||
useNavigateNoUpdate,
|
||||
} from '../../../application/CustomRouterContextProvider';
|
||||
import { Plugin } from '../../../application/Plugin';
|
||||
import { useAppSpin } from '../../../application/hooks/useAppSpin';
|
||||
import { useMenuTranslation } from '../../../schema-component/antd/menu/locale';
|
||||
@ -82,12 +88,11 @@ const MenuEditor = (props) => {
|
||||
const { setTitle: _setTitle } = useDocumentTitle();
|
||||
const setTitle = useCallback((title) => _setTitle(t(title)), []);
|
||||
const navigate = useNavigateNoUpdate();
|
||||
const params = useParams<any>();
|
||||
const location = useLocationNoUpdate();
|
||||
const isMatchAdmin = useMatch('/admin');
|
||||
const isMatchAdminName = useMatch('/admin/:name');
|
||||
const defaultSelectedUid = params.name;
|
||||
const isDynamicPage = !!defaultSelectedUid;
|
||||
const isMatchAdmin = useMatchAdmin();
|
||||
const isMatchAdminName = useMatchAdminName();
|
||||
const currentPageUid = useCurrentPageUid();
|
||||
const isDynamicPage = !!currentPageUid;
|
||||
const { sideMenuRef } = props;
|
||||
const ctx = useACLRoleContext();
|
||||
const [current, setCurrent] = useState(null);
|
||||
@ -126,7 +131,7 @@ const MenuEditor = (props) => {
|
||||
if (!isMatchAdminName || !isDynamicPage) return;
|
||||
|
||||
// url 为 `admin/xxx` 的情况
|
||||
const s = findByUid(schema, defaultSelectedUid);
|
||||
const s = findByUid(schema, currentPageUid);
|
||||
if (s) {
|
||||
setTitle(s.title);
|
||||
} else {
|
||||
@ -147,7 +152,9 @@ const MenuEditor = (props) => {
|
||||
if (sideMenuRef.current) {
|
||||
const pageType =
|
||||
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');
|
||||
if (pageType || isSettingPage) {
|
||||
sideMenuRef.current.style.display = 'none';
|
||||
@ -155,7 +162,7 @@ const MenuEditor = (props) => {
|
||||
sideMenuRef.current.style.display = 'block';
|
||||
}
|
||||
}
|
||||
}, [data?.data, params.name, sideMenuRef, location?.pathname]);
|
||||
}, [data?.data, currentPageUid, sideMenuRef, location?.pathname]);
|
||||
|
||||
const schema = useMemo(() => {
|
||||
const s = filterByACL(data?.data, ctx);
|
||||
@ -167,12 +174,12 @@ const MenuEditor = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (isMatchAdminName) {
|
||||
const s = findByUid(schema, defaultSelectedUid);
|
||||
const s = findByUid(schema, currentPageUid);
|
||||
if (s) {
|
||||
setTitle(s.title);
|
||||
}
|
||||
}
|
||||
}, [defaultSelectedUid, isMatchAdmin, isMatchAdminName, schema, setTitle]);
|
||||
}, [currentPageUid, isMatchAdmin, isMatchAdminName, schema, setTitle]);
|
||||
|
||||
useRequest(
|
||||
{
|
||||
@ -213,14 +220,14 @@ const MenuEditor = (props) => {
|
||||
);
|
||||
|
||||
const scope = useMemo(() => {
|
||||
return { useMenuProps, onSelect, sideMenuRef, defaultSelectedUid };
|
||||
return { useMenuProps, onSelect, sideMenuRef, defaultSelectedUid: currentPageUid };
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return render();
|
||||
}
|
||||
return (
|
||||
<SchemaIdContext.Provider value={defaultSelectedUid}>
|
||||
<SchemaIdContext.Provider value={currentPageUid}>
|
||||
<SchemaComponent distributed scope={scope} schema={schema} />
|
||||
</SchemaIdContext.Provider>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user