Skip to content

Commit

Permalink
Update docs & bugfix (#707)
Browse files Browse the repository at this point in the history
  • Loading branch information
janryWang committed Mar 8, 2020
1 parent 88e6b1b commit 835c68d
Show file tree
Hide file tree
Showing 59 changed files with 235 additions and 23 deletions.
6 changes: 0 additions & 6 deletions README.md
Expand Up @@ -77,12 +77,6 @@ https://formilyjs.org

[codesandbox](https://codesandbox.io/s/o5up7)

## Community

| Online Chat Room | 微信 | 钉钉 |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- |
| [gitter.im](https://gitter.im/alibaba-formily/community?source=orgpage) | <img width="200" src="https://img.alicdn.com/tfs/TB1jhm5VNYaK1RjSZFnXXa80pXa-620-824.png"/> | <img width="200" src="https://img.alicdn.com/tfs/TB1pHMzUrPpK1RjSZFFXXa5PpXa-620-818.png"/> |


## Contributors

Expand Down
6 changes: 0 additions & 6 deletions README.zh-cn.md
Expand Up @@ -76,12 +76,6 @@ https://formilyjs.org

[codesandbox](https://codesandbox.io/s/o5up7)

## 社区


| Online Chat Room | 微信 | 钉钉 |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- |
| [gitter.im](https://gitter.im/alibaba-formily/community?source=orgpage) | <img width="200" src="https://img.alicdn.com/tfs/TB1jhm5VNYaK1RjSZFnXXa80pXa-620-824.png"/> | <img width="200" src="https://img.alicdn.com/tfs/TB1pHMzUrPpK1RjSZFFXXa5PpXa-620-818.png"/> |

## 贡献者

Expand Down
2 changes: 2 additions & 0 deletions docs/zh-cn/SUMMARY.md
Expand Up @@ -13,6 +13,7 @@
- 实践教程
- [实现复杂联动](./schema-develop/complex-linkage.md)
- [实现复杂布局](./schema-develop/form-layout.md)
- [性能优化实践](./schema-develop/performance.md)
- [管理业务逻辑](./schema-develop/manage-business.md)
- [实现递归渲染组件](./schema-develop/recursive-render.md)
- [实现自增列表组件](./schema-develop/self-inc-component.md)
Expand All @@ -32,6 +33,7 @@
- 实践教程
- [实现复杂联动逻辑](./jsx-develop/complex-linkage.md)
- [实现复杂布局](./jsx-develop/form-layout.md)
- [性能优化实践](./jsx-develop/performance.md)
- [管理业务逻辑](./jsx-develop/manage-business.md)
- [实现自增列表组件](./jsx-develop/self-inc-component.md)
- [FAQ](./jsx-develop/faq.md)
Expand Down
79 changes: 79 additions & 0 deletions docs/zh-cn/jsx-develop/performance.md
@@ -0,0 +1,79 @@
# 性能优化实践

在Formily中,我们可以享受到精确更新的最大性能优势,也就是说,任何输入控件发生输入操作,都只会更新它自身,而不会整树更新,我们可以看看以下这张图:

![](https://img.alicdn.com/tfs/TB1m24nafc3T1VjSZLeXXbZsVXa-2186-1524.gif)

这也算是Formily的核心亮点之一,当然,Formily在联动场景下,同样可以做到精确更新,就是说,A/B两个字段发生联动,如果A控制B更新,那么只会更新B,同理,A控制B/C/D更新,那么也只会更新B/C/D,精准打击,让您的表单性能大大提升,特别在于某些表单项特别多的场景下,Formily的优势尤为明显。



总体来说,您只要使用了Formily,大部分的性能问题,都不需要考虑了。



## 但是

Formily也是存在一些无法解决的问题,需要您手动优化,主要有以下两个场景:

- 大数据场景会导致Formily计算卡顿
- 多字段批量更新会导致Formily渲染次数大大增加



## 大数据场景

这种场景的典型用例主要是TreeSelect或者地址选择或者富文本编辑器的json结构(比如draftjs),如果你的组件内部维护了极端复杂且巨大的数据,那么请不要将数据在FormState或者FieldState中维护,比如:

```tsx
<Form initialValues={{aa:BigData}}/> //这样传会导致性能问题

actions.setFieldState('aa',state=>{
state.props.enum = BigData //这样传也会导致性能问题
})
```

推荐使用context进行数据通信

```tsx
const BigDataContext = createContext({})

const MyComponent = ()=>{
const BigData = useContext(BigDataContext)
//消费大数据
}

<BigDataContext.Provider>
<Form components={{MyComponent}}>
<Field name="aa" type="object" x-component="MyComponent"/>
</Form>
</BigDataContext.Provider>


```

为什么要这样做?

主要原因是Formily内部会对状态做深度拷贝,同时也做了深度遍历脏检测,这种方式对于用户体验而言是更好了,但是在大数据场景下,就会出现性能问题,借助Context,我们可以做到绕过Formily的状态计算,直达组件,这样就可以很大程度的解决性能问题。

## 多字段批量更新

这种场景主要在联动场景,比如A字段要控制B/C/D/E等等字段的状态更新,如果控制的字段数量很少,那么相对而言是收益最高的,但是控制的字段数量很多,100+的字段数量,这样做,如果还是以精确渲染思路来的话,相当于会执行100+的渲染次数,同时Formily内部其实还会有一些中间状态,就相当于一次批量更新,会导致100 * n的渲染次数,那这样明显是起到了反作用,所以,针对这种场景,我们倒不如直接放开,让表单整树渲染,一次更新,这样对于多字段批量操作场景,性能一下子就上来了。下面是具体的API使用方法

```tsx

onFieldValueChange$('aa').subscribe(()=>{
actions.hostUpdate(()=>{
actions.setFieldState('bb.*',state=>{
state.visible = false
})
})
})
```



**案例解析**

- aa值变化时触发bb所有子节点隐藏
- 使用hostUpdate包装,可以在当前操作中阻止精确更新策略,在所有字段状态更新完毕之后直接走根组件重渲染策略,从而起到合并渲染的目的
79 changes: 79 additions & 0 deletions docs/zh-cn/schema-develop/performance.md
@@ -0,0 +1,79 @@
# 性能优化实践

在Formily中,我们可以享受到精确更新的最大性能优势,也就是说,任何输入控件发生输入操作,都只会更新它自身,而不会整树更新,我们可以看看以下这张图:

![](https://img.alicdn.com/tfs/TB1m24nafc3T1VjSZLeXXbZsVXa-2186-1524.gif)

这也算是Formily的核心亮点之一,当然,Formily在联动场景下,同样可以做到精确更新,就是说,A/B两个字段发生联动,如果A控制B更新,那么只会更新B,同理,A控制B/C/D更新,那么也只会更新B/C/D,精准打击,让您的表单性能大大提升,特别在于某些表单项特别多的场景下,Formily的优势尤为明显。



总体来说,您只要使用了Formily,大部分的性能问题,都不需要考虑了。



## 但是

Formily也是存在一些无法解决的问题,需要您手动优化,主要有以下两个场景:

- 大数据场景会导致Formily计算卡顿
- 多字段批量更新会导致Formily渲染次数大大增加



## 大数据场景

这种场景的典型用例主要是TreeSelect或者地址选择或者富文本编辑器的json结构(比如draftjs),如果你的组件内部维护了极端复杂且巨大的数据,那么请不要将数据在FormState或者FieldState中维护,比如:

```tsx
<SchemaForm initialValues={{aa:BigData}}/> //这样传会导致性能问题

actions.setFieldState('aa',state=>{
state.props.enum = BigData //这样传也会导致性能问题
})
```

推荐使用context进行数据通信

```tsx
const BigDataContext = createContext({})

const MyComponent = ()=>{
const BigData = useContext(BigDataContext)
//消费大数据
}

<BigDataContext.Provider>
<SchemaForm components={{MyComponent}}>
<Field name="aa" type="object" x-component="MyComponent"/>
</SchemaForm>
</BigDataContext.Provider>


```

为什么要这样做?

主要原因是Formily内部会对状态做深度拷贝,同时也做了深度遍历脏检测,这种方式对于用户体验而言是更好了,但是在大数据场景下,就会出现性能问题,借助Context,我们可以做到绕过Formily的状态计算,直达组件,这样就可以很大程度的解决性能问题。

## 多字段批量更新

这种场景主要在联动场景,比如A字段要控制B/C/D/E等等字段的状态更新,如果控制的字段数量很少,那么相对而言是收益最高的,但是控制的字段数量很多,100+的字段数量,这样做,如果还是以精确渲染思路来的话,相当于会执行100+的渲染次数,同时Formily内部其实还会有一些中间状态,就相当于一次批量更新,会导致100 * n的渲染次数,那这样明显是起到了反作用,所以,针对这种场景,我们倒不如直接放开,让表单整树渲染,一次更新,这样对于多字段批量操作场景,性能一下子就上来了。下面是具体的API使用方法

```tsx

onFieldValueChange$('aa').subscribe(()=>{
actions.hostUpdate(()=>{
actions.setFieldState('bb.*',state=>{
state.visible = false
})
})
})
```



**案例解析**

- aa值变化时触发bb所有子节点隐藏
- 使用hostUpdate包装,可以在当前操作中阻止精确更新策略,在所有字段状态更新完毕之后直接走根组件重渲染策略,从而起到合并渲染的目的
1 change: 1 addition & 0 deletions packages/antd-components/src/array-cards/style.ts
@@ -0,0 +1 @@
import 'antd/lib/card/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/array-table/style.ts
@@ -0,0 +1 @@
import 'antd/lib/table/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/checkbox/style.ts
@@ -0,0 +1 @@
import 'antd/lib/checkbox/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/circle-button/style.ts
@@ -0,0 +1 @@
import 'antd/lib/button/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/date-picker/style.ts
@@ -0,0 +1 @@
import 'antd/lib/date-picker/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/form-block/style.ts
@@ -0,0 +1 @@
import 'antd/lib/card/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/form-card/style.ts
@@ -0,0 +1 @@
import 'antd/lib/card/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/form-grid-col/style.ts
@@ -0,0 +1 @@
import 'antd/lib/col/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/form-grid-row/style.ts
@@ -0,0 +1 @@
import 'antd/lib/row/style/index'
2 changes: 2 additions & 0 deletions packages/antd-components/src/form-item-grid/style.ts
@@ -0,0 +1,2 @@
import 'antd/lib/row/style/index'
import 'antd/lib/col/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/form-step/style.ts
@@ -0,0 +1 @@
import 'antd/lib/steps/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/input/style.ts
@@ -0,0 +1 @@
import 'antd/lib/input/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/number-picker/style.ts
@@ -0,0 +1 @@
import 'antd/lib/input-number/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/password/style.ts
@@ -0,0 +1 @@
import 'antd/lib/input/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/radio/style.ts
@@ -0,0 +1 @@
import 'antd/lib/radio/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/range/style.ts
@@ -0,0 +1 @@
import 'antd/lib/slider/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/rating/style.ts
@@ -0,0 +1 @@
import 'antd/lib/rate/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/select/style.ts
@@ -0,0 +1 @@
import 'antd/lib/select/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/switch/style.ts
@@ -0,0 +1 @@
import 'antd/lib/switch/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/text-button/style.ts
@@ -0,0 +1 @@
import 'antd/lib/button/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/time-picker/style.ts
@@ -0,0 +1 @@
import 'antd/lib/time-picker/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/transfer/style.ts
@@ -0,0 +1 @@
import 'antd/lib/transfer/style/index'
1 change: 1 addition & 0 deletions packages/antd-components/src/upload/style.ts
@@ -0,0 +1 @@
import 'antd/lib/upload/style/index'
4 changes: 2 additions & 2 deletions packages/antd/src/adaptor/FormItem.tsx
Expand Up @@ -71,8 +71,8 @@ export const AntdSchemaFieldAdaptor: React.FC<ISchemaFieldAdaptorProps> = props
const formItemShallowProps = useShallowFormItem()

const mergedProps = {
...itemProps,
...formItemShallowProps
...formItemShallowProps,
...itemProps
}

const { labelCol, wrapperCol } = mergedProps
Expand Down
4 changes: 4 additions & 0 deletions packages/antd/src/style.ts
@@ -0,0 +1,4 @@
import 'antd/lib/form/style/index'
import 'antd/lib/button/style/index'
import 'antd/lib/row/style/index'
import 'antd/lib/col/style/index'
4 changes: 4 additions & 0 deletions packages/antd/src/types.ts
Expand Up @@ -37,6 +37,10 @@ export type IAntdFormItemProps = IFieldStateUIProps &
valueName?: string
eventName?: string
component?: React.JSXElementConstructor<any>
itemStyle?: {
[key: string]: string | number
}
itemClassName?: string
[key: string]: any
}

Expand Down
1 change: 1 addition & 0 deletions packages/next-components/src/array-cards/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/card/style'
1 change: 1 addition & 0 deletions packages/next-components/src/array-table/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/table/style'
1 change: 1 addition & 0 deletions packages/next-components/src/checkbox/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/checkbox/style'
1 change: 1 addition & 0 deletions packages/next-components/src/circle-button/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/button/style'
1 change: 1 addition & 0 deletions packages/next-components/src/date-picker/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/date-picker/style'
1 change: 1 addition & 0 deletions packages/next-components/src/form-block/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/card/style'
1 change: 1 addition & 0 deletions packages/next-components/src/form-card/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/card/style'
1 change: 1 addition & 0 deletions packages/next-components/src/form-grid-col/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/grid/style'
1 change: 1 addition & 0 deletions packages/next-components/src/form-grid-row/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/grid/style'
1 change: 1 addition & 0 deletions packages/next-components/src/form-item-grid/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/grid/style'
1 change: 1 addition & 0 deletions packages/next-components/src/form-step/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/step/style'
1 change: 1 addition & 0 deletions packages/next-components/src/input/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/input/style'
1 change: 1 addition & 0 deletions packages/next-components/src/number-picker/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/number-picker/style'
1 change: 1 addition & 0 deletions packages/next-components/src/password/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/input/style'
1 change: 1 addition & 0 deletions packages/next-components/src/radio/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/radio/style'
1 change: 1 addition & 0 deletions packages/next-components/src/range/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/range/style'
1 change: 1 addition & 0 deletions packages/next-components/src/rating/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/rating/style'
1 change: 1 addition & 0 deletions packages/next-components/src/select/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/select/style'
1 change: 1 addition & 0 deletions packages/next-components/src/switch/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/switch/style'
1 change: 1 addition & 0 deletions packages/next-components/src/text-button/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/button/style'
1 change: 1 addition & 0 deletions packages/next-components/src/time-picker/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/time-picker/style'
1 change: 1 addition & 0 deletions packages/next-components/src/transfer/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/transfer/style'
1 change: 1 addition & 0 deletions packages/next-components/src/upload/style.ts
@@ -0,0 +1 @@
import '@alifd/next/lib/upload/style'
8 changes: 5 additions & 3 deletions packages/next/src/adaptor/FormItem.tsx
Expand Up @@ -72,18 +72,20 @@ export const NextSchemaFieldAdaptor: React.FC<ISchemaFieldAdaptorProps> = props
const itemProps = computeSchemaExtendProps(props)

const mergedProps = {
...formItemShallowProps,
...itemProps,
...formItemShallowProps
}

const { labelCol, wrapperCol } = mergedProps

const addonAfter = mergedProps.addonAfter

delete mergedProps.addonAfter

const children = mergedProps.addonAfter ? (
const children = addonAfter ? (
<div style={{ display: 'flex', alignItems: 'center' }}>
<FormItemShallowProvider>{props.children}</FormItemShallowProvider>
{mergedProps.addonAfter}
{addonAfter}
</div>
) : (
<FormItemShallowProvider>{props.children}</FormItemShallowProvider>
Expand Down
3 changes: 3 additions & 0 deletions packages/next/src/style.ts
@@ -0,0 +1,3 @@
import '@alifd/next/lib/form/style'
import '@alifd/next/lib/button/style'
import '@alifd/next/lib/grid/style'

0 comments on commit 835c68d

Please sign in to comment.