React 表单设计 及 通用模式、组件抽取
React 表单设计
一份表单设计,其他涉及众多的细节。如果单独处理,无疑什么繁琐,充满众多细节。而其实上,作为「填表单」这个行为,它定制的部分却往往不多,比如使用者只需要关注「验证逻辑」、「显示什么错误信息」等高层的东西,而底层的行为和细节代码我们希望不需要过多关注。这样,「表单」就具有了一些逻辑上的共性,可以把这些东西抽取出来,封装成为组件,然后让使用者只需要关注高层的东西(逻辑、错误信息、验证方式等)。
基于这个考虑,「表单填写」这个场景有哪些细节需要考虑呢?不同的细节决定了怎样不同的技术实现方式呢?高层需要考虑的东西可以简化成什么呢?
基本问题
- 支持表单纯净性检查(pristine)
- 支持基本的验证功能(validation callback):
f(data) => errorMessage
- 支持基本的提交表单时验证功能(submit)
- 支持传出表单当前状态(已填数据、错误信息)
更细节问题
- 是否需要支持错误信息精确到字段级别?这可能有几种场景,但基本都是一个字段的(业务)合法性不能在填写当时验证(需要结合其他数据进行验证):
- 比如在填 B 字段的时候需要 A 字段数据,此时校验发现 A 字段是业务错误的,那么需要将字段 A 标红
- 比如在提交整个表单的时候发现 A 字段业务不合法,提示错误信息,并将其标红
- 是否需要支持字段的异步(后端)验证?提交时进行后端这是可以理解的,问题是字段级别是否也需要进行异步验证?这会关系到组件设计和应用架构的问题(错误信息是在哪管理,api 在哪里调用)
技术支持
下面谈谈这几种场景所需要的解决方案。
- pristine 纯净性检查:很简单。默认内置支持即可
- 基本的验证功能:很简单,提供一个
onValidate
即可,因为这里需要支持定制化的点就是这个 validator:validate(data) => errorMessage
。它需要实现这个契约 - 基本的提交表单时验证功能:很简单,提供一个
onSubmit
方法即可,这也是需要支持定制化的点 - 基本的表单当前状态维护:很简单,提供一个什么接口传出来即可。什么时候需要数据就什么时候传出来,错误信息同理
- 支持字段级别的错误定位:这个需要提供一个表单级别的 wrapper,由它来管理所有字段所产生的 error,由于有不同字段,肯定又需要 key 来区分,因此,这个从技术上需要两个东西:
- 提供
Form
表单级别的组件,它会通过某种契约知晓、控制组件之间的状态(显示、错误信息、数据、是否禁用等) - 提供
Field
字段级别的组件,它需要实现某种契约,与 Form 组件通晓状态
- 提供
比较难缠的是字段的异步(后端)验证这个问题。一般来说,表单的验证分为两种,一种是表单级别的验证,这种验证一定要通过后端验证;另一种是字段级别的验证,这种验证既可以使用前端验证,也可以使用后端验证。
其中,字段的前端验证,其实就是前面提供的 onValidate
接口,该种验证是同步完成的,通常速度极快,多只是校验表单数据是否为空,长度是否过长等「格式」上的问题。这种验证方式下,出错信息可以直接反映到字段上,通常来说,出错信息也是存储在组件的 state 中即可。
为字段验证带来挑战的是后端验证方式。由于需要走一趟后端,所以必然要调一趟 API,再从 API 的结果来确定是否有出错信息、出错信息是什么。而一般而言,我们的出错信息是在组件的 state 中管理的,而一般来说 API 作为有副作用的行为,发生地都在 redux/saga 中,最后必然是从 props 这种进来。那么,如何管理这两个不同的数据源?策略无外乎三种:
- 统一数据源到组件内部 state。这使得 API 必须写到组件内部,而非 thunk/saga 等专门管理的工具,不利于架构可追溯状态的应用,一定程度上违背了 react/redux 应用的架构和设计原则
- 统一数据源到 redux 并作为 props 使用。这解决了上一点的架构问题,但使得本来非常简单的 字段前端验证 校验也必须放到 redux 中做,使这部分校验变重了,也失去了一些可读性
- 不统一数据源,组件接受 props 和 state 产生的错误信息。这样必须还必须在组件内部「以某种形式管理」这两份错误信息,而这个管理方式就需要使用者来定制,并且还需要知道本来仅由 Validator 管理的 error message 的细节及其契约,API 就很不友好,也非常不组件化
API
综上,作为表单的设计者,在获得一个满意的解决方案前,你需要问自己,自己的表单复杂性有多高?是否需要支持字段级别的后端验证?是否需要支持跨字段的验证?是否需要定制 UI?有了确定的答案后,你才能知道这个表单需要什么技术支持、是否需要引入三方库,以及如何选择合适的三方库等。
三方库
- https://github.com/erikras/redux-form
- https://github.com/final-form/react-final-form
- https://github.com/selbekk/calidation 不支持 RN。从上面几点来看,跨字段验证,异步验证这两个事情似乎还没支持好
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 开发者是时候放弃敏捷了
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论