Replies: 3 comments 3 replies
-
autoCleanup不是一个完美解决方案试想一种场景,片段schema更新,是走的表单设计器搭建出来的,如果两份schema A/B,里面的差异只是对一个同名字段的title做修改,按照autoCleanup的思路,是无法自动清理的,因为它默认是基于type/x-component来识别是否清理字段,那这样的话就得定制differ函数。 但是,可能很多人定制differ函数就直接走深度递归判断了,可对于markup schema场景,深度递归脏检查的坑非常多,就比如:
显然,autoCleanup不是一个完美,且完备的方案 |
Beta Was this translation helpful? Give feedback.
2 replies
-
这么久了,这个问题还存在,局部schema更新后视图不会更新。 |
Beta Was this translation helpful? Give feedback.
0 replies
-
我发现了一个hack方法,const form = createForm();的时候 ,设置form.fields = {}的值,也可以让表单动态更新。 完整案例:
|
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
背景
在 http://localhost:8000/zh-CN/guide/advanced/controlled 文档中有讲到Formily本身是非受控的表单系统,为什么非受控,因为它是响应式表单模型,基于@formily/reactive可以获得更好的性能
但是,非受控带来的副作用问题是什么呢?
全量刷新Schema
先看个例子:
从这个例子上可以看到,其实我们就是想动态刷新Schema,但是实际测下来的效果是,schema更新了,UI没更新,原因就是因为所有字段模型都是存在form实例中的,字段属性,只会作为字段模型创建过程的初始化默认值,所以,如果我们要解决这个问题的话,就得销毁字段模型,让schema更新之后,以最新的属性作为初始化默认值,改法比较简单:
这样改了之后,创建form实例的过程就会受schema变化而重复创建。
当然,你可能会疑虑,频繁创建form实例会不会内存泄漏,放心,我们在FormProvider内部对form做了自动回收处理。
所以,对于schema全量刷新场景,使用useMemo就能完美解决UI同步的问题了。
可能又会有人问了,那如果希望保存表单的值给schema刷新的时候复用怎么做呢?其实这种场景在大多数场景下都不需要保存表单值的,因为json schema本身是描述数据类型的,json schema都变了,那对应的数据,就应该销毁掉。那如果硬是想要保存表单数据呢?
那就自己监听onFormValuesChange,在事件里自己收集表单数据,等下次重新创建form的时候,再传进去。
局部刷新Schema
试想一种场景,如果表单内的某个字段,需要动态联动一大片的字段显示隐藏,怎么做?
最简单用法,使用x-reactions主动联动即可,比如
但是,这种方案有两个问题:
但是实际场景可能是:
所以要解决这样的问题,基于显示隐藏的联动模式完全解决不了了,通过前面动态createForm的方式又会遇到如何把非片段型字段值(比如type)保存下来的问题。
所以,我们始终还是需要探索一种片段级更新schema的能力。
再思考一下本质问题,其实还是因为字段模型没有做到自动回收,所以UI就没法基于schema动态同步。
那么,如果设计一个基于schema变化的字段模型回收机制,是不是可以解决这个问题?
方案
基于schema的diff策略,做自动回收逻辑,如果schema发生:
回收策略
基于以上规则,我们实现一个diff函数,每次重新渲染的时候,计算一下,自动回收字段模型即可,因为回收了字段模型,就会重新创建字段模型,在创建的时候,就会以最新的props来创建,这就达到了UI同步的目的
具体API
SchemaField
RecursionField
为什么要给RecursionField也支持autoCleanup呢?主要有几点考虑:
总结
这么看来,借助autoCleanup API,我们已经根本上解决了formily 动态刷新schema的问题,那为什么不直接作为组件默认行为呢?
主要是autoCleanup是存在diff计算成本的,80%的场景都不会用到这样的能力,大多数都是简单的显示隐藏联动即可,所以完全不应该作为默认行为
而且,autoCleanup是一个并不推荐的方案,只有在极端复杂场景,不得已才用的,因为这里面的diff计算成本是真的很高
Q/A
对于纯jsx场景,这个问题该怎么解决呢?
我的理解,如果纯jsx场景,出现了动态渲染的问题,为啥不用schema模式呢?所以这个本身就有点伪需求了,当然,如果你硬是想要实现自动回收,那就自己手动删除字段模型和字段值吧,因为Form模型,该有的API都有,随便用户怎么玩
Beta Was this translation helpful? Give feedback.
All reactions