feat: improve code

This commit is contained in:
chenos 2022-01-21 14:04:15 +08:00
parent 84f3ed1564
commit 4715ba8d22
16 changed files with 90 additions and 54 deletions

View File

@ -473,7 +473,7 @@ export default function App() {
* defaultShowCode: true * defaultShowCode: true
* title: RouteSwitch + SchemaComponent * title: RouteSwitch + SchemaComponent
*/ */
import React, { useMemo } from 'react'; import React, { useMemo, useEffect } from 'react';
import { Link, MemoryRouter as Router } from 'react-router-dom'; import { Link, MemoryRouter as Router } from 'react-router-dom';
import { import {
RouteRedirectProps, RouteRedirectProps,
@ -483,6 +483,7 @@ import {
SchemaComponentProvider, SchemaComponentProvider,
SchemaComponent, SchemaComponent,
useDesignable, useDesignable,
useSchemaComponentContext,
} from '@nocobase/client'; } from '@nocobase/client';
import { Spin, Button } from 'antd'; import { Spin, Button } from 'antd';
import { observer, Schema } from '@formily/react'; import { observer, Schema } from '@formily/react';
@ -503,6 +504,10 @@ const Hello = observer(({ name }) => {
const RouteSchemaComponent = (props) => { const RouteSchemaComponent = (props) => {
const route = useRoute(); const route = useRoute();
const { reset } = useSchemaComponentContext();
useEffect(() => {
reset();
}, route.schema);
return <SchemaComponent schema={route.schema}/> return <SchemaComponent schema={route.schema}/>
} }

View File

@ -27,7 +27,8 @@
"axios": "^0.24.0", "axios": "^0.24.0",
"i18next": "^21.6.0", "i18next": "^21.6.0",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-i18next": "^11.15.1" "react-i18next": "^11.15.1",
"use-deep-compare-effect": "^1.8.1"
}, },
"peerDependencies": { "peerDependencies": {
"@types/react": ">=16.8.0 || >=17.0.0", "@types/react": ">=16.8.0 || >=17.0.0",

View File

@ -1,28 +1,28 @@
import React from 'react';
import { HashRouter, MemoryRouter } from 'react-router-dom';
import { import {
i18n, ACLShortcut,
compose, Action,
useRequest,
AuthLayout,
AdminLayout, AdminLayout,
AntdConfigProvider,
APIClientProvider, APIClientProvider,
AuthLayout,
CollectionManagerShortcut,
compose,
DesignableSwitch,
DocumentTitleProvider,
i18n,
Menu,
Page,
PluginManagerProvider,
RouteSwitch, RouteSwitch,
RouteSwitchProvider, RouteSwitchProvider,
AntdConfigProvider,
SchemaComponentProvider, SchemaComponentProvider,
Menu,
Action,
PluginManagerProvider,
DesignableSwitch,
CollectionManagerShortcut,
ACLShortcut,
SystemSettingsShortcut, SystemSettingsShortcut,
DocumentTitleProvider, useRequest
Page,
} from '@nocobase/client'; } from '@nocobase/client';
import { I18nextProvider } from 'react-i18next';
import { Spin } from 'antd'; import { Spin } from 'antd';
import React from 'react';
import { I18nextProvider } from 'react-i18next';
import { MemoryRouter } from 'react-router-dom';
import apiClient from './apiClient'; import apiClient from './apiClient';
const providers = [ const providers = [

View File

@ -43,11 +43,11 @@ PluginManager.Toolbar = (props: ToolbarProps) => {
<Menu style={{ width: '100%' }} selectable={false} mode={'horizontal'} theme={'dark'}> <Menu style={{ width: '100%' }} selectable={false} mode={'horizontal'} theme={'dark'}>
{items {items
.filter((item) => item.pin) .filter((item) => item.pin)
.map((item) => { .map((item, index) => {
const Action = get(components, item.component); const Action = get(components, item.component);
return ( return (
Action && ( Action && (
<ToolbarItemContext.Provider value={item}> <ToolbarItemContext.Provider key={index} value={item}>
<Action /> <Action />
</ToolbarItemContext.Provider> </ToolbarItemContext.Provider>
) )
@ -56,18 +56,18 @@ PluginManager.Toolbar = (props: ToolbarProps) => {
<Menu.SubMenu key={'more'} title={<MoreOutlined />}> <Menu.SubMenu key={'more'} title={<MoreOutlined />}>
{items {items
.filter((item) => !item.pin) .filter((item) => !item.pin)
.map((item) => { .map((item, index) => {
const Action = get(components, item.component); const Action = get(components, item.component);
return ( return (
Action && ( Action && (
<ToolbarItemContext.Provider value={item}> <ToolbarItemContext.Provider key={index} value={item}>
<Action /> <Action />
</ToolbarItemContext.Provider> </ToolbarItemContext.Provider>
) )
); );
})} })}
<Menu.Divider></Menu.Divider> <Menu.Divider key={'divider'}></Menu.Divider>
<Menu.Item disabled icon={<SettingOutlined />}> <Menu.Item key={'plugins'} disabled icon={<SettingOutlined />}>
</Menu.Item> </Menu.Item>
</Menu.SubMenu> </Menu.SubMenu>

View File

@ -21,6 +21,7 @@ export const Cascader = connect(
useLoadData = useDefLoadData, useLoadData = useDefLoadData,
changeOnSelectLast, changeOnSelectLast,
changeOnSelect, changeOnSelect,
maxLevel,
...others ...others
} = props; } = props;
const loadData = useLoadData(props); const loadData = useLoadData(props);

View File

@ -34,6 +34,7 @@ mock.onGet('/china_regions').reply(200, {
const useAsyncDataSource = (api: APIClient) => (field) => { const useAsyncDataSource = (api: APIClient) => (field) => {
field.loading = true; field.loading = true;
console.log('useAsyncDataSource');
api.request({ url: 'china_regions' }).then( api.request({ url: 'china_regions' }).then(
action.bound((res) => { action.bound((res) => {
field.dataSource = res?.data?.data || []; field.dataSource = res?.data?.data || [];

View File

@ -1,8 +1,8 @@
import { DesktopOutlined } from '@ant-design/icons';
import { observer, RecursionField, Schema, useFieldSchema } from '@formily/react';
import { Menu as AntdMenu } from 'antd';
import React, { createContext, useContext, useEffect, useState } from 'react'; import React, { createContext, useContext, useEffect, useState } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { Menu as AntdMenu } from 'antd';
import { Schema, observer, useFieldSchema, RecursionField } from '@formily/react';
import { DesktopOutlined } from '@ant-design/icons';
import { findKeysByUid, findMenuItem } from './util'; import { findKeysByUid, findMenuItem } from './util';
type ComposedMenu = React.FC<any> & { type ComposedMenu = React.FC<any> & {
@ -22,6 +22,7 @@ export const Menu: ComposedMenu = observer((props) => {
defaultOpenKeys: dOpenKeys, defaultOpenKeys: dOpenKeys,
...others ...others
} = props; } = props;
console.log('defaultSelectedUid', defaultSelectedUid)
const schema = useFieldSchema(); const schema = useFieldSchema();
const [defaultSelectedKeys, setDefaultSelectedKeys] = useState(() => { const [defaultSelectedKeys, setDefaultSelectedKeys] = useState(() => {
if (dSelectedKeys) { if (dSelectedKeys) {

View File

@ -1,8 +1,9 @@
import React from 'react';
import { Spin } from 'antd';
import { useRequest } from '../../api-client';
import { SchemaComponent } from './SchemaComponent';
import { Schema } from '@formily/react'; import { Schema } from '@formily/react';
import { Spin } from 'antd';
import React from 'react';
import { useRequest } from '../../api-client';
import { useSchemaComponentContext } from '../hooks';
import { SchemaComponent } from './SchemaComponent';
export interface RemoteSchemaComponentProps { export interface RemoteSchemaComponentProps {
scope?: any; scope?: any;
@ -15,20 +16,22 @@ export interface RemoteSchemaComponentProps {
const defaultTransform = (s: Schema) => s; const defaultTransform = (s: Schema) => s;
export const RemoteSchemaComponent: React.FC<RemoteSchemaComponentProps> = (props) => { const RequestSchemaComponent: React.FC<RemoteSchemaComponentProps> = (props) => {
const { hidden, scope, uid, onSuccess, schemaTransform = defaultTransform } = props; const { hidden, scope, uid, onSuccess, schemaTransform = defaultTransform } = props;
if (!uid) { const { reset } = useSchemaComponentContext();
return null;
}
const { data, loading } = useRequest( const { data, loading } = useRequest(
{ {
url: `/ui_schemas:getJsonSchema/${uid}`, url: `/ui_schemas:getJsonSchema/${uid}`,
}, },
{ {
refreshDeps: [uid], refreshDeps: [uid],
onSuccess, onSuccess(data) {
onSuccess && onSuccess(data);
reset && reset();
},
}, },
); );
if (loading) { if (loading) {
return <Spin />; return <Spin />;
} }
@ -37,3 +40,7 @@ export const RemoteSchemaComponent: React.FC<RemoteSchemaComponentProps> = (prop
} }
return <SchemaComponent scope={scope} schema={schemaTransform(data?.data || {})} />; return <SchemaComponent scope={scope} schema={schemaTransform(data?.data || {})} />;
}; };
export const RemoteSchemaComponent: React.FC<RemoteSchemaComponentProps> = (props) => {
return props.uid ? <RequestSchemaComponent {...props}/> : null;
};

View File

@ -1,5 +1,5 @@
import { ISchemaFieldProps, Schema } from '@formily/react'; import { ISchemaFieldProps, Schema } from '@formily/react';
import React, { useContext, useEffect, useMemo, useRef } from 'react'; import React, { useContext, useMemo } from 'react';
import { SchemaComponentContext } from '../context'; import { SchemaComponentContext } from '../context';
function toSchema(schema?: any) { function toSchema(schema?: any) {
@ -18,16 +18,8 @@ function toSchema(schema?: any) {
} }
export function SchemaComponent(props: ISchemaFieldProps) { export function SchemaComponent(props: ISchemaFieldProps) {
const { schema: defaultSchema, ...others } = props; const { schema, ...others } = props;
const { reset, SchemaField } = useContext(SchemaComponentContext); const { SchemaField } = useContext(SchemaComponentContext);
const schema = useMemo(() => toSchema(defaultSchema), []); const s = useMemo(() => toSchema(schema), []);
const isInitialMount = useRef(true); return <SchemaField {...others} schema={s} />;
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
reset();
}
}, [JSON.stringify(defaultSchema)]);
return <SchemaField {...others} schema={schema} />;
} }

View File

@ -29,7 +29,6 @@ export const SchemaComponentProvider: React.FC<ISchemaComponentProvider> = (prop
SchemaField, SchemaField,
components, components,
scope, scope,
refreshFormId: () => setFormId(uid()),
reset: () => setFormId(uid()), reset: () => setFormId(uid()),
refresh: () => setUid(uid()), refresh: () => setUid(uid()),
designable: active === 'true', designable: active === 'true',

View File

@ -2,4 +2,5 @@ export * from './useAttach';
export * from './useCompile'; export * from './useCompile';
export * from './useDesignable'; export * from './useDesignable';
export * from './useFieldProps'; export * from './useFieldProps';
export * from './useSchemaComponentContext';

View File

@ -1,9 +1,11 @@
import { useContext } from 'react';
import { compile } from '@formily/json-schema/lib/compiler'; import { compile } from '@formily/json-schema/lib/compiler';
import { useTranslation } from 'react-i18next'; import { SchemaExpressionScopeContext, SchemaOptionsContext } from '@formily/react';
export const useCompile = () => { export const useCompile = () => {
const { t } = useTranslation(); const options = useContext(SchemaOptionsContext);
const scope = useContext(SchemaExpressionScopeContext);
return (source: any) => { return (source: any) => {
return compile(source, { t }); return compile(source, { ...options.scope, ...scope });
}; };
}; };

View File

@ -0,0 +1,6 @@
import { useContext } from 'react';
import { SchemaComponentContext } from '../context';
export function useSchemaComponentContext() {
return useContext(SchemaComponentContext);
}

View File

@ -17,6 +17,14 @@ group:
## Hooks ## Hooks
### useSchemaComponentContext()
获取 SchemaComponent 的上下文
```ts
const { refresh, reset } = useSchemaComponentContext();
```
### useDesignable() ### useDesignable()
获取当前 schema 节点设计器的 API 获取当前 schema 节点设计器的 API

View File

@ -19,7 +19,6 @@ export interface ISchemaComponentContext {
scope?: any; scope?: any;
components?: SchemaReactComponents; components?: SchemaReactComponents;
refresh?: () => void; refresh?: () => void;
refreshFormId?: () => void;
reset?: () => void; reset?: () => void;
designable?: boolean; designable?: boolean;
setDesignable?: (value: boolean) => void; setDesignable?: (value: boolean) => void;

View File

@ -5452,6 +5452,11 @@ deprecation@^2.0.0, deprecation@^2.3.1:
resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
dequal@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d"
integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==
des.js@^1.0.0: des.js@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" resolved "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
@ -14631,6 +14636,14 @@ urllib@^2.33.1:
statuses "^1.3.1" statuses "^1.3.1"
utility "^1.16.1" utility "^1.16.1"
use-deep-compare-effect@^1.8.1:
version "1.8.1"
resolved "https://registry.npmjs.org/use-deep-compare-effect/-/use-deep-compare-effect-1.8.1.tgz#ef0ce3b3271edb801da1ec23bf0754ef4189d0c6"
integrity sha512-kbeNVZ9Zkc0RFGpfMN3MNfaKNvcLNyxOAAd9O4CBZ+kCBXXscn9s/4I+8ytUER4RDpEYs5+O6Rs4PqiZ+rHr5Q==
dependencies:
"@babel/runtime" "^7.12.5"
dequal "^2.0.2"
use-subscription@1.5.1: use-subscription@1.5.1:
version "1.5.1" version "1.5.1"
resolved "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" resolved "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"