Skip to content

Commit

Permalink
perf(antd/next): improve form-tab badge render performance (#3139)
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang committed May 23, 2022
1 parent 7847970 commit b3e4d79
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 52 deletions.
40 changes: 24 additions & 16 deletions packages/antd/src/array-tabs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
import React, { useState } from 'react'
import React, { Fragment, useState } from 'react'
import { Tabs, Badge } from 'antd'
import { ArrayField } from '@formily/core'
import {
useField,
observer,
useFieldSchema,
RecursionField,
ReactFC,
} from '@formily/react'
import { TabsProps } from 'antd/lib/tabs'

interface IFeedbackBadgeProps {
index: number
}

const FeedbackBadge: ReactFC<IFeedbackBadgeProps> = observer((props) => {
const field = useField<ArrayField>()
const tab = `${field.title || 'Untitled'} ${props.index + 1}`
const errors = field.errors.filter((error) =>
error.address.includes(`${field.address}.${props.index}`)
)
if (errors.length) {
return (
<Badge size="small" className="errors-badge" count={errors.length}>
{tab}
</Badge>
)
}
return <Fragment>{tab}</Fragment>
})

export const ArrayTabs: React.FC<React.PropsWithChildren<TabsProps>> = observer(
(props) => {
const field = useField<ArrayField>()
Expand All @@ -33,20 +54,7 @@ export const ArrayTabs: React.FC<React.PropsWithChildren<TabsProps>> = observer(
field.remove(index)
}
}
const badgedTab = (index: number) => {
const tab = `${field.title || 'Untitled'} ${index + 1}`
const errors = field.errors.filter((error) =>
error.address.includes(`${field.address}.${index}`)
)
if (errors.length) {
return (
<Badge size="small" className="errors-badge" count={errors.length}>
{tab}
</Badge>
)
}
return tab
}

return (
<Tabs
{...props}
Expand All @@ -67,7 +75,7 @@ export const ArrayTabs: React.FC<React.PropsWithChildren<TabsProps>> = observer(
key={key}
forceRender
closable={index !== 0}
tab={badgedTab(index)}
tab={<FeedbackBadge index={index} />}
>
<RecursionField schema={items} name={index} />
</Tabs.TabPane>
Expand Down
39 changes: 23 additions & 16 deletions packages/antd/src/form-tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { model, markRaw } from '@formily/reactive'
import { TabPaneProps, TabsProps } from 'antd/lib/tabs'
import {
useField,
ReactFC,
observer,
useFieldSchema,
RecursionField,
Expand All @@ -24,6 +25,11 @@ export interface IFormTabPaneProps extends TabPaneProps {
key: string | number
}

interface IFeedbackBadgeProps {
key: SchemaKey
tab: React.ReactNode
}

type ComposedFormTab = React.FC<React.PropsWithChildren<IFormTabProps>> & {
TabPane: React.FC<React.PropsWithChildren<IFormTabPaneProps>>
createFormTab: (defaultActiveKey?: string) => IFormTab
Expand All @@ -50,6 +56,22 @@ const useTabs = () => {
return tabs
}

const FeedbackBadge: ReactFC<IFeedbackBadgeProps> = observer((props) => {
const field = useField()
const errors = field.form.queryFeedbacks({
type: 'error',
address: `${field.address.concat(props.key)}.*`,
})
if (errors.length) {
return (
<Badge size="small" className="errors-badge" count={errors.length}>
{props.tab}
</Badge>
)
}
return <Fragment>{props.tab}</Fragment>
})

const createFormTab = (defaultActiveKey?: string) => {
const formTab = model({
activeKey: defaultActiveKey,
Expand All @@ -62,28 +84,13 @@ const createFormTab = (defaultActiveKey?: string) => {

export const FormTab: ComposedFormTab = observer(
({ formTab, ...props }: IFormTabProps) => {
const field = useField()
const tabs = useTabs()
const _formTab = useMemo(() => {
return formTab ? formTab : createFormTab()
}, [])
const prefixCls = usePrefixCls('formily-tab', props)
const activeKey = props.activeKey || _formTab?.activeKey

const badgedTab = (key: SchemaKey, props: any) => {
const errors = field.form.queryFeedbacks({
type: 'error',
address: `${field.address.concat(key)}.*`,
})
if (errors.length) {
return (
<Badge size="small" className="errors-badge" count={errors.length}>
{props.tab}
</Badge>
)
}
return props.tab
}
return (
<Tabs
{...props}
Expand All @@ -98,7 +105,7 @@ export const FormTab: ComposedFormTab = observer(
<Tabs.TabPane
key={key}
{...props}
tab={badgedTab(name, props)}
tab={<FeedbackBadge key={name} tab={props.tab} />}
forceRender
>
<RecursionField schema={schema} name={name} />
Expand Down
50 changes: 30 additions & 20 deletions packages/next/src/form-tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,29 @@ import {
import {
useField,
observer,
ReactFC,
useFieldSchema,
RecursionField,
} from '@formily/react'
import { Schema, SchemaKey } from '@formily/json-schema'
import cls from 'classnames'
import { usePrefixCls } from '../__builtins__'
export interface IFormTab {
activeKey: React.ReactText
setActiveKey(key: React.ReactText): void
activeKey: SchemaKey
setActiveKey(key: SchemaKey): void
}

export interface IFormTabProps extends TabsProps {
formTab?: IFormTab
}

export interface IFormTabPaneProps extends TabPaneProps {
key: React.ReactText
key: SchemaKey
}

interface IFeedbackBadgeProps {
key: SchemaKey
tab: React.ReactNode
}

type ComposedFormTab = React.FC<React.PropsWithChildren<IFormTabProps>> & {
Expand Down Expand Up @@ -64,31 +70,31 @@ const createFormTab = (defaultActiveKey?: string) => {
return markRaw(formTab)
}

const FeedbackBadge: ReactFC<IFeedbackBadgeProps> = observer((props) => {
const field = useField()
const errors = field.form.queryFeedbacks({
type: 'error',
address: `${field.address.concat(props.key)}.*`,
})
if (errors.length) {
return (
<Badge className="errors-badge" count={errors.length}>
{props.tab}
</Badge>
)
}
return <Fragment>{props.tab}</Fragment>
})

export const FormTab: ComposedFormTab = observer(
({ formTab, ...props }: IFormTabProps) => {
const field = useField()
const tabs = useTabs()
const _formTab = useMemo(() => {
return formTab ? formTab : createFormTab()
}, [])
const prefixCls = usePrefixCls('formily-tab', props)
const activeKey = props.activeKey || _formTab?.activeKey

const badgedTab = (key: SchemaKey, props: any) => {
const errors = field.form.queryFeedbacks({
type: 'error',
address: `${field.address.concat(key)}.*`,
})
if (errors.length) {
return (
<Badge className="errors-badge" count={errors.length}>
{props.tab}
</Badge>
)
}
return props.tab
}

return (
<Tabs
{...props}
Expand All @@ -101,7 +107,11 @@ export const FormTab: ComposedFormTab = observer(
lazyLoad={false}
>
{tabs.map(({ props, schema, name }, key) => (
<Tabs.Item key={key} {...props} tab={badgedTab(name, props)}>
<Tabs.Item
key={key}
{...props}
tab={<FeedbackBadge key={name} tab={props.tab} />}
>
<RecursionField schema={schema} name={name} />
</Tabs.Item>
))}
Expand Down

0 comments on commit b3e4d79

Please sign in to comment.