表单是业务系统前端开发中的最常见场景之一,市面上对于简化表单开发已经有了无数实践,比如组件库、配置化、低代码等等。但对于Mobx State Tree(以下简称MST)来说,与这些一站式的方案融合并不太容易,开发表单往往需要针对每一个表单新建一个model type,或者对于单例表单,在已有的model type中创建对应field的prop以及对应的action。这两种方法虽然都可以完成表单开发的需求,但不够优雅,如果再搭配上校验相关的功能,就会产生大量的表单伴生状态,在日积月累的业务迭代后,会显著降低model的可维护性。
针对这个问题,我开发了一个可以根据传入schema生成自定义MST type的工具,旨在对每个表单的伴随状态实现优雅的封装。生成的自定义type带有schema中field的prop,以及改变prop的对应action,还提供了校验功能,可以根据校验结果输出表单fields的值或校验产生的错误。此外,这个包的功能很克制,和一站式解决方案不同,只是帮助处理field输入、管理、校验,表单的提交、联动、初始化等重业务逻辑的部分依旧交给开发者直接处理,提供了更好的灵活性,Mobx State Tree的使用者可以尝试一下。
链接
安装
npm i mst-form-type -S
注意:需要自行安装mobx-state-tree的5.0.0以上版本。
使用
import createForm from 'mst-form-type'
type schema = {
[key: string]: {
default: string | number
validator?: 'required' | ((...args: any[]) => boolean) | RegExp | undefined | null
}
}
const Main = types.model('Main', {
form: createForm(schema, 'name?')
...
})
// change field value
form.setValue({ key: 'key', value: 'value' })
// submit form
form.submit() => { key1: value1, key2: value2, ... }
APIs
mst-form-type通过default export提供了一个函数接受schema,生成新的type,将该form相关的伴随状态都包裹在了新type之内。这样,每个schema生成的form都拥有不同的type,实现了form之间的隔离。而这些form的自定义type全部基于一个base type,提供了统一的校验、提交等功能,保证了API的统一。
schema
type schema = {
[key: string]: {
default: string | number
validator?: 'required' | ((...args: any[]) => boolean) | RegExp | undefined | null
}
}
schema是一个关键,它采用了Key-Value对象的形式,定义了form的形态。并且可以借助其他工具,用同一个schema生成表单的UI。
key
key对应form中的每一个field的key,它必须是唯一的,并且会在setValue()的方法中用来设定对应field的值。
default
field的默认值,可以是string或number,生成的新type中对应prop的值会根据default的类型决定。如果组件返回的值是对象或者数组,可以暂时序列化后存储或找到字符串类型的key值。后续版本可能会内置序列化的功能,但目前不想增加核心不相关的功能。
validator
这是一个可选key,所有的validator都会在valid()方法中根据类型被调用。
'required' 代表这个field必须有值,且能转化为true的值,否则就不是必须的了。
((...args: any[]) => boolean) 代表validator是一个返回boolean的函数,field值会作为参数传入该函数,然后调用函数返回结果。如果返回true,说明校验通过。
RegExp 代表validator是一个正则,field的值会传入RegExp.test()并调用。如果返回true,说明校验通过。
undefined | null 会被忽略,直接不写这个key就好。
props
fields
每个schema中的key都会作为一个field成为新type中的一个prop。这个prop的类型会根据这个key的default字段决定,可以是string 或 number。
submission
一个最近一次成功提交的快照,以Key-Value的形式展示,通常情况下不需要直接访问,因为submit()会返回这个值。
error
一个Key-Value形式的对象,包含所有不通过校验的field错误信息,目前错误信息是根据validator类型提供的,暂不支持自定义。这个prop每次valid()都会被整体更新。通常情况下不需要直接访问,因为有错误的情况下,submit()会返回这个值,并在控制台中报错。
status
展示form的状态,有4个值:'init', 'pending', 'success', 'error',根据form状态改变,可以用来判断form状态。
actions
default export
这个默认export的方法调用后可以创建一个新type。新type接受描述form的schema作为参数,并且根据schema生成对应的prop,以及其他的初始化动作。该方法还可以接受第二个参数作为新type的名字。目前该名字没什么用,debug的时候可能需要,所以作为可选参数。
init(schema)
这个方法会在新的type创建之后自动调用,根据schema对新的type进行初始化。一般情况下不需要手动调用,除非想再对该表单进行一次初始化。
initVal({ key1: value1, key2: value2, ... })
这个方法用来初始化表单的所有field。通常情况下不需要调用,因为init(schema)已经根据schema进行了所有field的初始化。
这个方法只会对已有的field进行值的初始化,当前不存的field将被忽略。
setValue({ key, value })
核心方法,根据key来进行field赋值。新值需要和default的类型相同。internalStatus 是保留字段,不可使用。
valid()
调用schema中所有的validator,并将结果以Key-Value的形式存入error prop。通常不需要手动调用,会在submit()之前自动调用。
submit()
在所有field的值都通过校验后,该方法以Key-Value的形式返回所有field,并将当前的结果存到submission prop中。如果有值未通过校验,则以Key-Value的形式返回这些值对应的报错信息。
这个方法不执行实际的提交操作,只是输出当前fields的值。真正的异步提交操作需要手动处理
reset()
重制表单,将status设置为init,清除submission和error,并将所有的field都设定为schema中default的值。