如何用RxJS实现Redux Form

看这篇文章之前,你需要掌握的知识:

React

RxJS (至少需要知道 Subject 是什么)

背景

form 可以说是 web 开发中的最大的难题之一。跟普通的组件相比,form 具有以下几个特点:

1、更多的用户交互。
这意味着可能需要大量的自定义组件,比如 DataPicker,Upload,AutoComplete 等等。

3、频繁的状态改变。
每当用户输入一个值,都可能会对应用状态造成改变,从而需要更新表单元素或者显示错误信息。

3、表单校验,也就是对用户输入数据的有效性进行验证。
表单验证的形式也很多,比如边输入边验证,失去焦点后验证,或者在提交表单之前验证等等。

4、异步网络通信。
当用户输入和异步网络通信同时存在时,需要考虑的东西就更多了。就比如 AutoComplete,需要根据用户的输入去异步获取相应的数据,如果用户每输入一次就发起一次请求,会对资源造成很大浪费。因为每一次输入都是异步获取数据的,那么连续两次用户输入拿到的数据也有可能存在 "后发先至" 的问题。

正因为以上这些特点,使 form 的开发变得困难重重。在接下来的章节中,我们会将 RxJS 和 Form 结合起来,帮助我们更好的去解决这些问题。

HTML Form

在实现我们自己的 Form 组件之前,让我们先来参考一下原生的 HTML Form。

保存表单状态

对于一个 Form 组件来说,需要保存所有表单元素的信息(如 value, validity 等),HTML Form 也不例外。

那么,HTML Form 将表单状态保存在什么地方?如何才能获取表单元素信息?

主要有以下几种方法:

document.forms 会返回所有 <form> 表单节点。

HTMLFormElement.elements 返回所有表单元素。

event.target.elements 也能获取所有表单元素。

document.forms[0].elements[0].value; // 获取第一个 form 中第一个表单元素的值 const form = document.querySelector("form"); form.elements[0].value; form.addEventListener('submit', function(event) { console.log(event.target.elements[0].value); });

Validation

表单校验的类型一般分为两种:

内置表单校验。默认会在提交表单的时候自动触发。通过设置 novalidate 属性可以关闭浏览器的自动校验。

JavaScript 校验。

<form novalidate> <input required/> <input type='password' required minlength="6" maxlength="6"/> <input type='email'/> <input type='submit' value='submit'/> </form>

存在的问题

定制化很难。 比如不支持 Inline Validation,只有 submit 时才能校验表单,且 error message 的样式不能自定义。

难以应对复杂场景。 比如表单元素的嵌套等。

Input 组件的行为不统一,从而难以获取表单元素的值。 比如 checkbox 和 multiple select,取值的时候不能直接取 value,还需要额外的转换。

var $form = document.querySelector('form'); function getFormValues(form) { var values = {}; var elements = form.elements; // elemtns is an array-like object for (var i = 0; i < elements.length; i++) { var input = elements[i]; if (input.name) { switch (input.type.toLowerCase()) { case 'checkbox': if (input.checked) { values[input.name] = input.checked; } break; case 'select-multiple': values[input.name] = values[input.name] || []; for (var j = 0; j < input.length; j++) { if (input[j].selected) { values[input.name].push(input[j].value); } } break; default: values[input.name] = input.value; break; } } } return values; } $form.addEventListener('submit', function(event) { event.preventDefault(); getFormValues(event.target); console.log(event.target.elements); console.log(getFormValues(event.target)); });

React Rx Form

感兴趣的同学可以先去看一下源码 https://github.com/reeli/react-rx-form

React 与 RxJS

RxJS 是一个非常强大的数据管理工具,但它并不具备用户界面渲染的功能,而 React 却特别擅长处理界面。那何不将它们的长处结合起来?用 React 和 RxJS 来解决我们的 Form 难题。既然知道了它们各自的长处,所以分工也就比较明确了:

RxJS 负责管理状态,React 负责渲染界面。

设计思路

与 Redux Form 不同的是,我们不会将 form 的状态存储在 store 中,而是直接保存在 <Form/> 组件中。然后利用 RxJS 将数据通知给每一个 <Field/> ,然后 <Field/> 组件会根据数据去决定自己是否需要更新 UI,需要更新则调用 setState ,否则什么也不做。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/6d9f3e7fe4431ed38f048de92b3a28a4.html