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
-
背景
在 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