-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(shared): support BigData (#708)
- Loading branch information
Showing
11 changed files
with
191 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,87 @@ | ||
# 性能优化实践 | ||
|
||
在Formily中,我们可以享受到精确更新的最大性能优势,也就是说,任何输入控件发生输入操作,都只会更新它自身,而不会整树更新,我们可以看看以下这张图: | ||
在 Formily 中,我们可以享受到精确更新的最大性能优势,也就是说,任何输入控件发生输入操作,都只会更新它自身,而不会整树更新,我们可以看看以下这张图: | ||
|
||
 | ||
|
||
这也算是Formily的核心亮点之一,当然,Formily在联动场景下,同样可以做到精确更新,就是说,A/B两个字段发生联动,如果A控制B更新,那么只会更新B,同理,A控制B/C/D更新,那么也只会更新B/C/D,精准打击,让您的表单性能大大提升,特别在于某些表单项特别多的场景下,Formily的优势尤为明显。 | ||
|
||
|
||
|
||
总体来说,您只要使用了Formily,大部分的性能问题,都不需要考虑了。 | ||
|
||
这也算是 Formily 的核心亮点之一,当然,Formily 在联动场景下,同样可以做到精确更新,就是说,A/B 两个字段发生联动,如果 A 控制 B 更新,那么只会更新 B,同理,A 控制 B/C/D 更新,那么也只会更新 B/C/D,精准打击,让您的表单性能大大提升,特别在于某些表单项特别多的场景下,Formily 的优势尤为明显。 | ||
|
||
总体来说,您只要使用了 Formily,大部分的性能问题,都不需要考虑了。 | ||
|
||
## 但是 | ||
|
||
Formily也是存在一些无法解决的问题,需要您手动优化,主要有以下两个场景: | ||
|
||
- 大数据场景会导致Formily计算卡顿 | ||
- 多字段批量更新会导致Formily渲染次数大大增加 | ||
|
||
Formily 也是存在一些无法解决的问题,需要您手动优化,主要有以下两个场景: | ||
|
||
- 大数据场景会导致 Formily 计算卡顿 | ||
- 多字段批量更新会导致 Formily 渲染次数大大增加 | ||
|
||
## 大数据场景 | ||
|
||
这种场景的典型用例主要是TreeSelect或者地址选择或者富文本编辑器的json结构(比如draftjs),如果你的组件内部维护了极端复杂且巨大的数据,那么请不要将数据在FormState或者FieldState中维护,比如: | ||
这种场景的典型用例主要是 TreeSelect 或者地址选择或者富文本编辑器的 json 结构(比如 draftjs),如果你的组件内部维护了极端复杂且巨大的数据,那么请不要将数据在 FormState 或者 FieldState 中维护,比如: | ||
|
||
```tsx | ||
<Form initialValues={{aa:BigData}}/> //这样传会导致性能问题 | ||
|
||
actions.setFieldState('aa',state=>{ | ||
state.props.enum = BigData //这样传也会导致性能问题 | ||
}) | ||
import { Form } from '@formily/antd' | ||
|
||
const App = () => ( | ||
<Form | ||
initialValues={{ aa: BigData }} //这样传会导致性能问题 | ||
effects={$ => { | ||
$('onFieldChange', 'bb').subscribe(() => { | ||
actions.setFieldState('aa', state => { | ||
state.props.enum = BigData //这样传也会导致性能问题 | ||
}) | ||
}) | ||
}} | ||
/> | ||
) | ||
``` | ||
|
||
推荐使用context进行数据通信 | ||
推荐使用内置 BigData 数据结构进行包装 | ||
|
||
```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> | ||
|
||
|
||
import { BigData, Form } from '@formily/antd' | ||
|
||
const specialStructure = new BigData({ | ||
compare(a, b) { | ||
//你可以定制当前大数据的对比函数,也可以不传,不传则是引用对比 | ||
}, | ||
clone(value) { | ||
//你可以定制当前大数据的克隆函数,也可以不传,如果不传,拷贝则是引用传递 | ||
} | ||
}) | ||
const App = () => ( | ||
<Form | ||
initialValues={{ aa: specialStructure.create(BigData) }} //注意要保证create传入的数据是Immutable的数据 | ||
effects={$ => { | ||
$('onFieldChange', 'bb').subscribe(() => { | ||
actions.setFieldState('aa', state => { | ||
state.props.enum = specialStructure.create(BigData) //注意要保证create传入的数据是Immutable的数据 | ||
}) | ||
}) | ||
}} | ||
/> | ||
) | ||
``` | ||
|
||
为什么要这样做? | ||
|
||
主要原因是Formily内部会对状态做深度拷贝,同时也做了深度遍历脏检测,这种方式对于用户体验而言是更好了,但是在大数据场景下,就会出现性能问题,借助Context,我们可以做到绕过Formily的状态计算,直达组件,这样就可以很大程度的解决性能问题。 | ||
主要原因是 Formily 内部会对状态做深度拷贝,同时也做了深度遍历脏检测,这种方式对于用户体验而言是更好了,但是在大数据场景下,就会出现性能问题,借助 BigData 数据结构,我们可以更加定制化的控制脏检查和拷贝算法,保证特殊场景的性能平滑不受影响 | ||
|
||
## 多字段批量更新 | ||
|
||
这种场景主要在联动场景,比如A字段要控制B/C/D/E等等字段的状态更新,如果控制的字段数量很少,那么相对而言是收益最高的,但是控制的字段数量很多,100+的字段数量,这样做,如果还是以精确渲染思路来的话,相当于会执行100+的渲染次数,同时Formily内部其实还会有一些中间状态,就相当于一次批量更新,会导致100 * n的渲染次数,那这样明显是起到了反作用,所以,针对这种场景,我们倒不如直接放开,让表单整树渲染,一次更新,这样对于多字段批量操作场景,性能一下子就上来了。下面是具体的API使用方法 | ||
这种场景主要在联动场景,比如 A 字段要控制 B/C/D/E 等等字段的状态更新,如果控制的字段数量很少,那么相对而言是收益最高的,但是控制的字段数量很多,100+的字段数量,这样做,如果还是以精确渲染思路来的话,相当于会执行 100+的渲染次数,同时 Formily 内部其实还会有一些中间状态,就相当于一次批量更新,会导致 100 \* n 的渲染次数,那这样明显是起到了反作用,所以,针对这种场景,我们倒不如直接放开,让表单整树渲染,一次更新,这样对于多字段批量操作场景,性能一下子就上来了。下面是具体的 API 使用方法 | ||
|
||
```tsx | ||
|
||
onFieldValueChange$('aa').subscribe(()=>{ | ||
actions.hostUpdate(()=>{ | ||
actions.setFieldState('bb.*',state=>{ | ||
state.visible = false | ||
}) | ||
}) | ||
onFieldValueChange$('aa').subscribe(() => { | ||
actions.hostUpdate(() => { | ||
actions.setFieldState('bb.*', state => { | ||
state.visible = false | ||
}) | ||
}) | ||
}) | ||
``` | ||
|
||
|
||
|
||
**案例解析** | ||
|
||
- aa值变化时触发bb所有子节点隐藏 | ||
- 使用hostUpdate包装,可以在当前操作中阻止精确更新策略,在所有字段状态更新完毕之后直接走根组件重渲染策略,从而起到合并渲染的目的 | ||
- aa 值变化时触发 bb 所有子节点隐藏 | ||
- 使用 hostUpdate 包装,可以在当前操作中阻止精确更新策略,在所有字段状态更新完毕之后直接走根组件重渲染策略,从而起到合并渲染的目的 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,88 @@ | ||
# 性能优化实践 | ||
|
||
在Formily中,我们可以享受到精确更新的最大性能优势,也就是说,任何输入控件发生输入操作,都只会更新它自身,而不会整树更新,我们可以看看以下这张图: | ||
在 Formily 中,我们可以享受到精确更新的最大性能优势,也就是说,任何输入控件发生输入操作,都只会更新它自身,而不会整树更新,我们可以看看以下这张图: | ||
|
||
 | ||
|
||
这也算是Formily的核心亮点之一,当然,Formily在联动场景下,同样可以做到精确更新,就是说,A/B两个字段发生联动,如果A控制B更新,那么只会更新B,同理,A控制B/C/D更新,那么也只会更新B/C/D,精准打击,让您的表单性能大大提升,特别在于某些表单项特别多的场景下,Formily的优势尤为明显。 | ||
|
||
|
||
|
||
总体来说,您只要使用了Formily,大部分的性能问题,都不需要考虑了。 | ||
|
||
这也算是 Formily 的核心亮点之一,当然,Formily 在联动场景下,同样可以做到精确更新,就是说,A/B 两个字段发生联动,如果 A 控制 B 更新,那么只会更新 B,同理,A 控制 B/C/D 更新,那么也只会更新 B/C/D,精准打击,让您的表单性能大大提升,特别在于某些表单项特别多的场景下,Formily 的优势尤为明显。 | ||
|
||
总体来说,您只要使用了 Formily,大部分的性能问题,都不需要考虑了。 | ||
|
||
## 但是 | ||
|
||
Formily也是存在一些无法解决的问题,需要您手动优化,主要有以下两个场景: | ||
|
||
- 大数据场景会导致Formily计算卡顿 | ||
- 多字段批量更新会导致Formily渲染次数大大增加 | ||
|
||
Formily 也是存在一些无法解决的问题,需要您手动优化,主要有以下两个场景: | ||
|
||
- 大数据场景会导致 Formily 计算卡顿 | ||
- 多字段批量更新会导致 Formily 渲染次数大大增加 | ||
|
||
## 大数据场景 | ||
|
||
这种场景的典型用例主要是TreeSelect或者地址选择或者富文本编辑器的json结构(比如draftjs),如果你的组件内部维护了极端复杂且巨大的数据,那么请不要将数据在FormState或者FieldState中维护,比如: | ||
这种场景的典型用例主要是 TreeSelect 或者地址选择或者富文本编辑器的 json 结构(比如 draftjs),如果你的组件内部维护了极端复杂且巨大的数据,那么请不要将数据在 FormState 或者 FieldState 中维护,比如: | ||
|
||
```tsx | ||
<SchemaForm initialValues={{aa:BigData}}/> //这样传会导致性能问题 | ||
|
||
actions.setFieldState('aa',state=>{ | ||
state.props.enum = BigData //这样传也会导致性能问题 | ||
}) | ||
import { SchemaForm } from '@formily/antd' | ||
|
||
const App = () => ( | ||
<SchemaForm | ||
initialValues={{ aa: BigData }} //这样传会导致性能问题 | ||
effects={$ => { | ||
$('onFieldChange', 'bb').subscribe(() => { | ||
actions.setFieldState('aa', state => { | ||
state.props.enum = BigData //这样传也会导致性能问题 | ||
}) | ||
}) | ||
}} | ||
/> | ||
) | ||
``` | ||
|
||
推荐使用context进行数据通信 | ||
推荐使用内置 BigData 数据结构进行包装 | ||
|
||
```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> | ||
|
||
import { BigData, SchemaForm } from '@formily/antd' | ||
|
||
const specialStructure = new BigData({ | ||
compare(a, b) { | ||
//你可以定制当前大数据的对比函数,也可以不传,不传则是引用对比 | ||
}, | ||
clone(value) { | ||
//你可以定制当前大数据的克隆函数,也可以不传,如果不传,拷贝则是引用传递 | ||
} | ||
}) | ||
|
||
const App = () => ( | ||
<SchemaForm | ||
initialValues={{ aa: specialStructure.create(BigData) }} //注意要保证create传入的数据是Immutable的数据 | ||
effects={$ => { | ||
$('onFieldChange', 'bb').subscribe(() => { | ||
actions.setFieldState('aa', state => { | ||
state.props.enum = specialStructure.create(BigData) //注意要保证create传入的数据是Immutable的数据 | ||
}) | ||
}) | ||
}} | ||
/> | ||
) | ||
``` | ||
|
||
为什么要这样做? | ||
|
||
主要原因是Formily内部会对状态做深度拷贝,同时也做了深度遍历脏检测,这种方式对于用户体验而言是更好了,但是在大数据场景下,就会出现性能问题,借助Context,我们可以做到绕过Formily的状态计算,直达组件,这样就可以很大程度的解决性能问题。 | ||
主要原因是 Formily 内部会对状态做深度拷贝,同时也做了深度遍历脏检测,这种方式对于用户体验而言是更好了,但是在大数据场景下,就会出现性能问题,借助 BigData 数据结构,我们可以更加定制化的控制脏检查和拷贝算法,保证特殊场景的性能平滑不受影响 | ||
|
||
## 多字段批量更新 | ||
|
||
这种场景主要在联动场景,比如A字段要控制B/C/D/E等等字段的状态更新,如果控制的字段数量很少,那么相对而言是收益最高的,但是控制的字段数量很多,100+的字段数量,这样做,如果还是以精确渲染思路来的话,相当于会执行100+的渲染次数,同时Formily内部其实还会有一些中间状态,就相当于一次批量更新,会导致100 * n的渲染次数,那这样明显是起到了反作用,所以,针对这种场景,我们倒不如直接放开,让表单整树渲染,一次更新,这样对于多字段批量操作场景,性能一下子就上来了。下面是具体的API使用方法 | ||
这种场景主要在联动场景,比如 A 字段要控制 B/C/D/E 等等字段的状态更新,如果控制的字段数量很少,那么相对而言是收益最高的,但是控制的字段数量很多,100+的字段数量,这样做,如果还是以精确渲染思路来的话,相当于会执行 100+的渲染次数,同时 Formily 内部其实还会有一些中间状态,就相当于一次批量更新,会导致 100 \* n 的渲染次数,那这样明显是起到了反作用,所以,针对这种场景,我们倒不如直接放开,让表单整树渲染,一次更新,这样对于多字段批量操作场景,性能一下子就上来了。下面是具体的 API 使用方法 | ||
|
||
```tsx | ||
|
||
onFieldValueChange$('aa').subscribe(()=>{ | ||
actions.hostUpdate(()=>{ | ||
actions.setFieldState('bb.*',state=>{ | ||
state.visible = false | ||
}) | ||
}) | ||
onFieldValueChange$('aa').subscribe(() => { | ||
actions.hostUpdate(() => { | ||
actions.setFieldState('bb.*', state => { | ||
state.visible = false | ||
}) | ||
}) | ||
}) | ||
``` | ||
|
||
|
||
|
||
**案例解析** | ||
|
||
- aa值变化时触发bb所有子节点隐藏 | ||
- 使用hostUpdate包装,可以在当前操作中阻止精确更新策略,在所有字段状态更新完毕之后直接走根组件重渲染策略,从而起到合并渲染的目的 | ||
- aa 值变化时触发 bb 所有子节点隐藏 | ||
- 使用 hostUpdate 包装,可以在当前操作中阻止精确更新策略,在所有字段状态更新完毕之后直接走根组件重渲染策略,从而起到合并渲染的目的 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.