mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 23:46:02 +00:00
perf(react-router-hooks): improve performance
This commit is contained in:
parent
c838ac70ad
commit
f395e814f2
@ -7,8 +7,19 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import React, { FC, useEffect } from 'react';
|
||||
import { Location, NavigateFunction, NavigateOptions, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { Schema } from '@formily/json-schema';
|
||||
import _ from 'lodash';
|
||||
import React, { FC, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Location,
|
||||
NavigateFunction,
|
||||
NavigateOptions,
|
||||
useHref,
|
||||
useLocation,
|
||||
useNavigate,
|
||||
useParams,
|
||||
useSearchParams,
|
||||
} from 'react-router-dom';
|
||||
|
||||
const NavigateNoUpdateContext = React.createContext<NavigateFunction>(null);
|
||||
NavigateNoUpdateContext.displayName = 'NavigateNoUpdateContext';
|
||||
@ -34,6 +45,61 @@ MatchAdminNameContext.displayName = 'MatchAdminNameContext';
|
||||
const IsInSettingsPageContext = React.createContext<boolean>(false);
|
||||
IsInSettingsPageContext.displayName = 'IsInSettingsPageContext';
|
||||
|
||||
const CurrentTabUidContext = React.createContext<string>('');
|
||||
CurrentTabUidContext.displayName = 'CurrentTabUidContext';
|
||||
|
||||
const SearchParamsContext = React.createContext<URLSearchParams>(new URLSearchParams());
|
||||
SearchParamsContext.displayName = 'SearchParamsContext';
|
||||
|
||||
const RouterBasenameContext = React.createContext<string>('');
|
||||
RouterBasenameContext.displayName = 'RouterBasenameContext';
|
||||
|
||||
const IsSubPageClosedByPageMenuContext = React.createContext<{
|
||||
isSubPageClosedByPageMenu: boolean;
|
||||
setFieldSchema: React.Dispatch<React.SetStateAction<Schema>>;
|
||||
}>({
|
||||
isSubPageClosedByPageMenu: false,
|
||||
setFieldSchema: () => {},
|
||||
});
|
||||
IsSubPageClosedByPageMenuContext.displayName = 'IsSubPageClosedByPageMenuContext';
|
||||
|
||||
export const IsSubPageClosedByPageMenuProvider: FC = ({ children }) => {
|
||||
const params = useParams();
|
||||
const prevParamsRef = useRef<any>({});
|
||||
const [fieldSchema, setFieldSchema] = useState<Schema>(null);
|
||||
|
||||
const isSubPageClosedByPageMenu = useMemo(() => {
|
||||
const result =
|
||||
_.isEmpty(params['*']) &&
|
||||
fieldSchema?.['x-component-props']?.openMode === 'page' &&
|
||||
!!prevParamsRef.current['*']?.includes(fieldSchema['x-uid']);
|
||||
|
||||
prevParamsRef.current = params;
|
||||
|
||||
return result;
|
||||
}, [fieldSchema, params]);
|
||||
|
||||
const value = useMemo(() => ({ isSubPageClosedByPageMenu, setFieldSchema }), [isSubPageClosedByPageMenu]);
|
||||
|
||||
return (
|
||||
<IsSubPageClosedByPageMenuContext.Provider value={value}>{children}</IsSubPageClosedByPageMenuContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* see: https://stackoverflow.com/questions/50449423/accessing-basename-of-browserouter
|
||||
* @returns {string} basename
|
||||
*/
|
||||
const RouterBasenameProvider: FC = ({ children }) => {
|
||||
const basenameOfCurrentRouter = useHref('/');
|
||||
return <RouterBasenameContext.Provider value={basenameOfCurrentRouter}>{children}</RouterBasenameContext.Provider>;
|
||||
};
|
||||
|
||||
const SearchParamsProvider: FC = ({ children }) => {
|
||||
const [searchParams] = useSearchParams();
|
||||
return <SearchParamsContext.Provider value={searchParams}>{children}</SearchParamsContext.Provider>;
|
||||
};
|
||||
|
||||
const IsInSettingsPageProvider: FC = ({ children }) => {
|
||||
const isInSettingsPage = useLocation().pathname.includes('/settings');
|
||||
return <IsInSettingsPageContext.Provider value={isInSettingsPage}>{children}</IsInSettingsPageContext.Provider>;
|
||||
@ -62,6 +128,11 @@ export const CurrentPageUidProvider: FC = ({ children }) => {
|
||||
return <CurrentPageUidContext.Provider value={params.name}>{children}</CurrentPageUidContext.Provider>;
|
||||
};
|
||||
|
||||
export const CurrentTabUidProvider: FC = ({ children }) => {
|
||||
const params = useParams();
|
||||
return <CurrentTabUidContext.Provider value={params.tabUid}>{children}</CurrentTabUidContext.Provider>;
|
||||
};
|
||||
|
||||
/**
|
||||
* When the URL changes, components that use `useNavigate` will re-render.
|
||||
* This provider provides a `navigateNoUpdate` method that can avoid re-rendering.
|
||||
@ -107,7 +178,7 @@ const LocationSearchProvider: FC = ({ children }) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* use `useNavigateNoUpdate` to avoid components that use `useNavigateNoUpdate` re-rendering.
|
||||
* use `useNavigateNoUpdate` to avoid components re-rendering.
|
||||
* @returns
|
||||
*/
|
||||
export const useNavigateNoUpdate = () => {
|
||||
@ -115,7 +186,7 @@ export const useNavigateNoUpdate = () => {
|
||||
};
|
||||
|
||||
/**
|
||||
* use `useLocationNoUpdate` to avoid components that use `useLocationNoUpdate` re-rendering.
|
||||
* use `useLocationNoUpdate` to avoid components re-rendering.
|
||||
* @returns
|
||||
*/
|
||||
export const useLocationNoUpdate = () => {
|
||||
@ -146,6 +217,32 @@ export const useIsInSettingsPage = () => {
|
||||
return React.useContext(IsInSettingsPageContext);
|
||||
};
|
||||
|
||||
export const useCurrentTabUid = () => {
|
||||
return React.useContext(CurrentTabUidContext);
|
||||
};
|
||||
|
||||
export const useCurrentSearchParams = () => {
|
||||
return React.useContext(SearchParamsContext);
|
||||
};
|
||||
|
||||
export const useRouterBasename = () => {
|
||||
return React.useContext(RouterBasenameContext);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to determine if the user closed the sub-page by clicking on the page menu
|
||||
* @returns
|
||||
*/
|
||||
export const useIsSubPageClosedByPageMenu = (fieldSchema: Schema) => {
|
||||
const { isSubPageClosedByPageMenu, setFieldSchema } = React.useContext(IsSubPageClosedByPageMenuContext);
|
||||
|
||||
useEffect(() => {
|
||||
setFieldSchema(fieldSchema);
|
||||
}, [fieldSchema, setFieldSchema]);
|
||||
|
||||
return isSubPageClosedByPageMenu;
|
||||
};
|
||||
|
||||
export const CustomRouterContextProvider: FC = ({ children }) => {
|
||||
return (
|
||||
<NavigateNoUpdateProvider>
|
||||
@ -154,7 +251,11 @@ export const CustomRouterContextProvider: FC = ({ children }) => {
|
||||
<LocationSearchProvider>
|
||||
<MatchAdminProvider>
|
||||
<MatchAdminNameProvider>
|
||||
<IsInSettingsPageProvider>{children}</IsInSettingsPageProvider>
|
||||
<SearchParamsProvider>
|
||||
<RouterBasenameProvider>
|
||||
<IsInSettingsPageProvider>{children}</IsInSettingsPageProvider>
|
||||
</RouterBasenameProvider>
|
||||
</SearchParamsProvider>
|
||||
</MatchAdminNameProvider>
|
||||
</MatchAdminProvider>
|
||||
</LocationSearchProvider>
|
||||
|
@ -11,4 +11,3 @@ export * from './useApp';
|
||||
export * from './useAppSpin';
|
||||
export * from './usePlugin';
|
||||
export * from './useRouter';
|
||||
export * from './useRouterBasename';
|
||||
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { useHref } from 'react-router-dom';
|
||||
|
||||
/**
|
||||
* see: https://stackoverflow.com/questions/50449423/accessing-basename-of-browserouter
|
||||
* @returns {string} basename
|
||||
*/
|
||||
export const useRouterBasename = () => {
|
||||
const basenameOfCurrentRouter = useHref('/');
|
||||
return basenameOfCurrentRouter;
|
||||
};
|
@ -62,7 +62,7 @@ export function withDynamicSchemaProps<T = any>(
|
||||
options: WithSchemaHookOptions = {},
|
||||
) {
|
||||
const displayName = options.displayName || Component.displayName || Component.name;
|
||||
const ComponentWithProps: ComponentType<T> = (props) => {
|
||||
const ComponentWithProps: ComponentType<T> = React.memo((props) => {
|
||||
const { dn, findComponent } = useDesignable();
|
||||
const useComponentPropsStr = useMemo(() => {
|
||||
const xComponent = dn.getSchemaAttribute('x-component');
|
||||
@ -85,7 +85,7 @@ export function withDynamicSchemaProps<T = any>(
|
||||
}, [schemaProps, props]);
|
||||
|
||||
return <Component {...memoProps}>{props.children}</Component>;
|
||||
};
|
||||
});
|
||||
|
||||
Component.displayName = displayName;
|
||||
ComponentWithProps.displayName = `withSchemaProps(${displayName})`;
|
||||
|
@ -11,14 +11,14 @@ import { ApiOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
import { Button, Dropdown, Tooltip } from 'antd';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useApp } from '../application';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useApp, useNavigateNoUpdate } from '../application';
|
||||
import { useCompile } from '../schema-component';
|
||||
import { useToken } from '../style';
|
||||
|
||||
export const PluginManagerLink = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const navigate = useNavigateNoUpdate();
|
||||
const { token } = useToken();
|
||||
return (
|
||||
<Tooltip title={t('Plugin manager')}>
|
||||
@ -47,8 +47,11 @@ export const SettingsCenterDropdown = () => {
|
||||
return {
|
||||
key: setting.name,
|
||||
icon: setting.icon,
|
||||
label: setting.link ? <div onClick={() => window.open(setting.link)}>{compile(setting.title)}</div> :
|
||||
label: setting.link ? (
|
||||
<div onClick={() => window.open(setting.link)}>{compile(setting.title)}</div>
|
||||
) : (
|
||||
<Link to={setting.path}>{compile(setting.title)}</Link>
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [app, t]);
|
||||
|
@ -35,6 +35,8 @@ import {
|
||||
} from '../../../';
|
||||
import {
|
||||
CurrentPageUidProvider,
|
||||
CurrentTabUidProvider,
|
||||
IsSubPageClosedByPageMenuProvider,
|
||||
useCurrentPageUid,
|
||||
useIsInSettingsPage,
|
||||
useMatchAdmin,
|
||||
@ -467,41 +469,45 @@ export const InternalAdminLayout = () => {
|
||||
<Layout>
|
||||
<GlobalStyleForAdminLayout />
|
||||
<CurrentPageUidProvider>
|
||||
<Layout.Header className={layoutHeaderCss}>
|
||||
<div style={style1}>
|
||||
<div style={style2}>
|
||||
<div className={className1}>
|
||||
{result?.data?.data?.logo?.url ? (
|
||||
<img className={className2} src={result?.data?.data?.logo?.url} />
|
||||
) : (
|
||||
<span style={fontSizeStyle} className={className3}>
|
||||
{result?.data?.data?.title}
|
||||
</span>
|
||||
)}
|
||||
<CurrentTabUidProvider>
|
||||
<IsSubPageClosedByPageMenuProvider>
|
||||
<Layout.Header className={layoutHeaderCss}>
|
||||
<div style={style1}>
|
||||
<div style={style2}>
|
||||
<div className={className1}>
|
||||
{result?.data?.data?.logo?.url ? (
|
||||
<img className={className2} src={result?.data?.data?.logo?.url} />
|
||||
) : (
|
||||
<span style={fontSizeStyle} className={className3}>
|
||||
{result?.data?.data?.title}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={className4}>
|
||||
<SetThemeOfHeaderSubmenu>
|
||||
<MenuEditor sideMenuRef={sideMenuRef} />
|
||||
</SetThemeOfHeaderSubmenu>
|
||||
</div>
|
||||
</div>
|
||||
<div className={className5}>
|
||||
<PinnedPluginList />
|
||||
<ConfigProvider theme={theme}>
|
||||
<Divider type="vertical" />
|
||||
</ConfigProvider>
|
||||
<Help />
|
||||
<CurrentUser />
|
||||
</div>
|
||||
</div>
|
||||
<div className={className4}>
|
||||
<SetThemeOfHeaderSubmenu>
|
||||
<MenuEditor sideMenuRef={sideMenuRef} />
|
||||
</SetThemeOfHeaderSubmenu>
|
||||
</div>
|
||||
</div>
|
||||
<div className={className5}>
|
||||
<PinnedPluginList />
|
||||
<ConfigProvider theme={theme}>
|
||||
<Divider type="vertical" />
|
||||
</ConfigProvider>
|
||||
<Help />
|
||||
<CurrentUser />
|
||||
</div>
|
||||
</div>
|
||||
</Layout.Header>
|
||||
<AdminSideBar sideMenuRef={sideMenuRef} />
|
||||
{/* Use the "nb-subpages-slot-without-header-and-side" class name to locate the position of the subpages */}
|
||||
<Layout.Content className={`${layoutContentClass} nb-subpages-slot-without-header-and-side`}>
|
||||
<header className={layoutContentHeaderClass}></header>
|
||||
<Outlet />
|
||||
{/* {service.contentLoading ? render() : <Outlet />} */}
|
||||
</Layout.Content>
|
||||
</Layout.Header>
|
||||
<AdminSideBar sideMenuRef={sideMenuRef} />
|
||||
{/* Use the "nb-subpages-slot-without-header-and-side" class name to locate the position of the subpages */}
|
||||
<Layout.Content className={`${layoutContentClass} nb-subpages-slot-without-header-and-side`}>
|
||||
<header className={layoutContentHeaderClass}></header>
|
||||
<Outlet />
|
||||
{/* {service.contentLoading ? render() : <Outlet />} */}
|
||||
</Layout.Content>
|
||||
</IsSubPageClosedByPageMenuProvider>
|
||||
</CurrentTabUidProvider>
|
||||
</CurrentPageUidProvider>
|
||||
</Layout>
|
||||
);
|
||||
|
@ -8,9 +8,8 @@
|
||||
*/
|
||||
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import _ from 'lodash';
|
||||
import React, { createContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import React, { createContext, useEffect, useMemo, useState } from 'react';
|
||||
import { useIsSubPageClosedByPageMenu } from '../../../application/CustomRouterContextProvider';
|
||||
import { useDataBlockRequest } from '../../../data-source';
|
||||
import { useCurrentPopupContext } from '../page/PagePopups';
|
||||
import { getBlockService, storeBlockService } from '../page/pagePopupUtils';
|
||||
@ -19,37 +18,13 @@ import { ActionContextProps } from './types';
|
||||
export const ActionContext = createContext<ActionContextProps>({});
|
||||
ActionContext.displayName = 'ActionContext';
|
||||
|
||||
/**
|
||||
* Used to determine if the user closed the sub-page by clicking on the page menu
|
||||
* @returns
|
||||
*/
|
||||
const useIsSubPageClosedByPageMenu = () => {
|
||||
// Used to trigger re-rendering when URL changes
|
||||
const params = useParams();
|
||||
const prevParamsRef = useRef<any>({});
|
||||
const fieldSchema = useFieldSchema();
|
||||
|
||||
const isSubPageClosedByPageMenu = useMemo(() => {
|
||||
const result =
|
||||
_.isEmpty(params['*']) &&
|
||||
fieldSchema?.['x-component-props']?.openMode === 'page' &&
|
||||
!!prevParamsRef.current['*']?.includes(fieldSchema['x-uid']);
|
||||
|
||||
prevParamsRef.current = params;
|
||||
|
||||
return result;
|
||||
}, [fieldSchema, params]);
|
||||
|
||||
return isSubPageClosedByPageMenu;
|
||||
};
|
||||
|
||||
export const ActionContextProvider: React.FC<ActionContextProps & { value?: ActionContextProps }> = React.memo(
|
||||
(props) => {
|
||||
const [submitted, setSubmitted] = useState(false); //是否有提交记录
|
||||
const { visible } = { ...props, ...props.value } || {};
|
||||
const { setSubmitted: setParentSubmitted } = { ...props, ...props.value };
|
||||
const service = useBlockServiceInActionButton();
|
||||
const isSubPageClosedByPageMenu = useIsSubPageClosedByPageMenu();
|
||||
const isSubPageClosedByPageMenu = useIsSubPageClosedByPageMenu(useFieldSchema());
|
||||
|
||||
useEffect(() => {
|
||||
if (visible === false && service && !service.loading && (submitted || isSubPageClosedByPageMenu)) {
|
||||
|
@ -17,12 +17,16 @@ import classNames from 'classnames';
|
||||
import React, { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { NavigateFunction, Outlet, useOutletContext, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { NavigateFunction, Outlet, useOutletContext } from 'react-router-dom';
|
||||
import { FormDialog } from '..';
|
||||
import { antTableCell } from '../../../acl/style';
|
||||
import { useRequest } from '../../../api-client';
|
||||
import { useNavigateNoUpdate } from '../../../application/CustomRouterContextProvider';
|
||||
import { useRouterBasename } from '../../../application/hooks/useRouterBasename';
|
||||
import {
|
||||
useCurrentSearchParams,
|
||||
useCurrentTabUid,
|
||||
useNavigateNoUpdate,
|
||||
useRouterBasename,
|
||||
} from '../../../application/CustomRouterContextProvider';
|
||||
import { useDocumentTitle } from '../../../document-title';
|
||||
import { useGlobalTheme } from '../../../global-theme';
|
||||
import { Icon } from '../../../icon';
|
||||
@ -36,25 +40,24 @@ import { ErrorFallback } from '../error-fallback';
|
||||
import { useStyles } from './Page.style';
|
||||
import { PageDesigner, PageTabDesigner } from './PageTabDesigner';
|
||||
|
||||
export const Page = (props) => {
|
||||
export const Page = React.memo((props: any) => {
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const dn = useDesignable();
|
||||
const { theme } = useGlobalTheme();
|
||||
const { getAriaLabel } = useGetAriaLabelOfSchemaInitializer();
|
||||
const { tabUid } = useParams();
|
||||
const currentTabUid = useCurrentTabUid();
|
||||
const basenameOfCurrentRouter = useRouterBasename();
|
||||
|
||||
const disablePageHeader = fieldSchema['x-component-props']?.disablePageHeader;
|
||||
const enablePageTabs = fieldSchema['x-component-props']?.enablePageTabs;
|
||||
const options = useContext(SchemaOptionsContext);
|
||||
const navigate = useNavigateNoUpdate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const searchParams = useCurrentSearchParams();
|
||||
const loading = false;
|
||||
const activeKey = useMemo(
|
||||
// 处理 searchParams 是为了兼容旧版的 tab 参数
|
||||
() => tabUid || searchParams.get('tab') || Object.keys(fieldSchema.properties || {}).shift(),
|
||||
[fieldSchema.properties, searchParams, tabUid],
|
||||
() => currentTabUid || searchParams.get('tab') || Object.keys(fieldSchema.properties || {}).shift(),
|
||||
[fieldSchema.properties, searchParams, currentTabUid],
|
||||
);
|
||||
const { wrapSSR, hashId, componentCls } = useStyles();
|
||||
const { token } = useToken();
|
||||
@ -168,14 +171,19 @@ export const Page = (props) => {
|
||||
) : null;
|
||||
}, [activeKey, enablePageTabs, handleTabsChange, items, tabBarExtraContent, tabBarStyle]);
|
||||
|
||||
const outletContext = useMemo(
|
||||
() => ({ loading, disablePageHeader, enablePageTabs, fieldSchema, tabUid: currentTabUid }),
|
||||
[currentTabUid, disablePageHeader, enablePageTabs, fieldSchema, loading],
|
||||
);
|
||||
|
||||
return wrapSSR(
|
||||
<div className={`${componentCls} ${hashId} ${antTableCell}`}>
|
||||
<NocoBasePageHeader footer={footer} />
|
||||
<div className="nb-page-wrapper">
|
||||
<ErrorBoundary FallbackComponent={ErrorFallback} onError={console.error}>
|
||||
{tabUid ? (
|
||||
{currentTabUid ? (
|
||||
// used to match the rout with name "admin.page.tab"
|
||||
<Outlet context={{ loading, disablePageHeader, enablePageTabs, fieldSchema, tabUid }} />
|
||||
<Outlet context={outletContext} />
|
||||
) : (
|
||||
<>
|
||||
<PageContent
|
||||
@ -193,7 +201,9 @@ export const Page = (props) => {
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Page.displayName = 'NocoBasePage';
|
||||
|
||||
export const PageTabs = () => {
|
||||
const { loading, disablePageHeader, enablePageTabs, fieldSchema, tabUid } = useOutletContext<any>();
|
||||
|
@ -109,6 +109,7 @@ const PopupTabsPropsProvider: FC = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const displayNone = { display: 'none' };
|
||||
const PagePopupsItemProvider: FC<{
|
||||
params: PopupParams;
|
||||
context: PopupContext;
|
||||
@ -180,7 +181,7 @@ const PagePopupsItemProvider: FC<{
|
||||
{/* Pass the service of the block where the button is located down, to refresh the block's data when the popup is closed */}
|
||||
<BlockRequestContextProvider recordRequest={storedContext.service}>
|
||||
<PopupTabsPropsProvider>
|
||||
<div style={{ display: 'none' }}>{children}</div>
|
||||
<div style={displayNone}>{children}</div>
|
||||
</PopupTabsPropsProvider>
|
||||
</BlockRequestContextProvider>
|
||||
</DataBlockProvider>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useCallback } from 'react';
|
||||
import { useCollection_deprecated } from '../../collection-manager';
|
||||
import { useCollection } from '../../data-source/collection/CollectionProvider';
|
||||
|
||||
/**
|
||||
* label = 'schema-initializer' + x-component + [x-initializer] + [collectionName] + [postfix]
|
||||
@ -18,7 +18,7 @@ import { useCollection_deprecated } from '../../collection-manager';
|
||||
|
||||
export const useGetAriaLabelOfSchemaInitializer = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { name } = useCollection_deprecated();
|
||||
const { name } = useCollection() || {};
|
||||
const getAriaLabel = useCallback(
|
||||
(postfix?: string) => {
|
||||
if (!fieldSchema) return '';
|
||||
|
@ -34,7 +34,7 @@ const useContextVariable = (): VariableOption => {
|
||||
const { field, blockData, rowKey, collection: collectionName } = tableBlockContext || {};
|
||||
|
||||
const contextData = useMemo(
|
||||
() => blockData?.data?.filter((v) => (field?.data?.selectedRowKeys || [])?.includes(v[rowKey])),
|
||||
() => blockData?.data?.filter?.((v) => (field?.data?.selectedRowKeys || [])?.includes(v[rowKey])),
|
||||
[field?.data?.selectedRowKeys, rowKey, blockData],
|
||||
);
|
||||
|
||||
|
@ -139,7 +139,7 @@ export const useUpdateCollectionActionAndRefreshCM = (options) => {
|
||||
const ctx = useActionContext();
|
||||
const { name } = useParams();
|
||||
const { refresh } = useResourceActionContext();
|
||||
const { resource, targetKey } = useResourceContext();
|
||||
const { targetKey } = useResourceContext();
|
||||
const { [targetKey]: filterByTk } = useRecord();
|
||||
const api = useAPIClient();
|
||||
const dm = useDataSourceManager();
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
import { css, cx } from '@nocobase/client';
|
||||
import React from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import Device from './iOS6';
|
||||
|
||||
export const MobileDevice: React.FC = (props) => {
|
||||
|
@ -8,10 +8,8 @@ import {
|
||||
MobileTitleProvider,
|
||||
} from '@nocobase/plugin-mobile/client';
|
||||
import React from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
const Demo = () => {
|
||||
const { pathname } = useLocation();
|
||||
return (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<MobileTitleProvider title="Title">
|
||||
|
Loading…
Reference in New Issue
Block a user