在前面一篇文章中,笔者简单的对比了 antd Form
和 react-hook-form
,以及介绍了 react-form-simple 的基本用法。
本文将就业务场景举例来更加具体的阐述 react-form-simple 的用法。
什么是react-form-simple
一个基于react的可受控可扩展的轻量级表单库,以最快的速度以及最精简的代码渲染出一个可受控的表单。React-form-simple除了集成自身功能之外,还具有非常可扩展的接口, 并可与第三方ui集成使用。
为什么选择react-form-simple
-
通过创建一个可观察对象来观察表单的模型操作, 表单项的受控直接通过
_.
赋值。 -
简单几行代码就可以完成表单受控, 无需关心受控逻辑, 无需关心受控过程, 只需要知道受控结果和如何应用你的受控状态。
-
每个表单项之间的渲染自动完全隔离, 不需要自行组织组件隔离。这将能够更快的处理表单输入后的响应速度, 以及很大程度的避免在大型动态数据下造成的页面卡顿。
-
具有数据观测功能, 可以在某些场景下对整个表单或者某个具体的表单项进行单一或者统一的观察监测, 可以在你需要用表单项最新的值进行渲染的地方进行值的订阅。
-
灵活的使用方式, 灵活的页面布局组合, 开发者可以根据自己的喜好和场景使用某种方式以及内置布局。在大多数场景下, 无需开发者手动布局。
-
简约的 API 设计, 在操作表单的过程中, 简单的只需要引入两个 API, 就可以完成大部分工作。
-
高度可扩展的表单接口, 在一些复杂需求或者定制化场景中, 开发者可以自行定制表单的控制逻辑。
-
可以轻易集成在你的 UI 或者 第三方库中。
-
完整的类型推断。
流程架构
通过创建一个可观察的表单模型数据,使用useForm hook 暴露出的 render 方法渲染出一个表单项视图,通过render函数将模型数据和这个表单项视图结合起来,生成一座受控的桥梁,以实现双向受控。 当模型数据更新,会将自动更新表单项视图, 当表单项视图被更改,也将影响到模型数据的更新。这个过程,不需要开发者去关心和手动管理。
搭建起一座受控桥梁后,使用 useSubscribe 便能追踪到表单模型数据的变化。从而在外部订阅相关字段后,能够将字段渲染在表单视图之外。
依赖层
- react16.9.0 +
实现层
- useForm
- FormItem
基本用法
js
import React, { useEffect, useState } from 'react';
import { useForm } from 'react-form-simple';
export default function App() {
const { render, model } = useForm({ name: 'name' });
const [modelState, setModelState] = useState('');
const renderName = render('name')(<input className="input" />);
const onSubmit = () => setModelState(JSON.stringify(model));
return (
<>
{renderName}
{modelState}
<button onClick={onSubmit}>submit</button>
</>
);
}
如上所示,通过render函数将渲染视图和模型数据关联起来,这样便自动的创建了一个受控桥梁。
登录
js
import { useForm } from "react-form-simple";
export default function App() {
const { model, render, validate } = useForm({ user: "", password: "" });
const renerUser = render("user", {
label: "用户名",
rules: {
required: "用户名不能为空",
},
})(<input placeholder="请输入" />);
const renerPassword = render("password", {
label: "密码",
rules: { required: "密码不能为空" },
})(<input />);
return (
<div style={{ width: "600px", margin: "300px auto" }}>
<div>{renerUser}</div>
<div>{renerPassword}</div>
<div>
<button
onClick={async () => {
await validate();
login(model).then((res) => {
/** code.... */
});
}}
>
login
</button>
</div>
</div>
);
}
效果
集成第三方控件登录
下面是一个使用antd进行登录的例子
js
import { useForm } from "react-form-simple";
import { Input } from "antd";
export default function App() {
const { model, render, validate } = useForm({ user: "", password: "" });
const renerUser = render("user", {
label: "用户名",
rules: {
required: "用户名不能为空",
},
defineProps(options) {
return { status: options.isError ? "error" : "" };
},
})(<Input placeholder="请输入" />);
const renerPassword = render("password", {
label: "密码",
rules: { required: "密码不能为空" },
defineProps(options) {
return { status: options.isError ? "error" : "" };
},
})(<Input />);
return (
<div style={{ width: "600px", margin: "300px auto" }}>
<div>{renerUser}</div>
<div>{renerPassword}</div>
<div>
<button
onClick={async () => {
await validate();
login(model).then((res) => {
/** code.... */
});
}}
>
login
</button>
</div>
</div>
);
}
效果如下:
在校验不通过的时候,提示错误并使antd的Input输入框标红。关于更多属性,请看文档
不止antd,react-form-simpe 能够与你项目中使用的任何UI库轻易集成。
显示基本信息
下面是一个显示基本信息的例子,并有只读状态和编辑状态。
js
import { useForm } from "react-form-simple";
import { Input, Radio, Select } from "antd";
import { useEffect, useState } from "react";
export default function App() {
const [readOnly, setReadOnly] = useState(true);
const { model, render } = useForm(
{
name: "",
age: "",
sex: 1,
select: 1,
},
{ labelPosition: "top", readOnly }
);
useEffect(() => {
setTimeout(() => {
model.name = "name";
model.age = "16";
}, 1500);
}, []);
return (
<div style={{ width: "600px", margin: "300px auto" }}>
<div>
{render("name", { label: "name" })(<Input />)}
{render("age", { label: "age" })(<Input />)}
{render("sex", {
label: "age",
defineProps(options) {
return { disabled: options.attrs.readOnly };
},
})(
<Radio.Group
options={[
{ label: "男", value: 1 },
{ label: "女", value: 2 },
]}
/>
)}
{render("select", {
label: "select",
defineProps(options) {
return { disabled: options.attrs.readOnly };
},
})(
<Select
style={{ width: "300px" }}
options={[
{ label: "select1", value: 1 },
{ label: "select2", value: 2 },
]}
/>
)}
</div>
<div>
<button
style={{ marginRight: "10px" }}
onClick={() => {
setReadOnly(false);
}}
>
edit
</button>
<button
style={{ marginRight: "10px" }}
onClick={() => {
setReadOnly(true);
}}
>
back
</button>
</div>
</div>
);
}
但在项目中开发人员已经确定了要使用什么UI库,开发人员可以基于此在这个上面做一层更精度的适合项目UI库的封装,以减少更多的代码产量。
订阅最新值
js
import React from 'react';
import { useForm } from 'react-form-simple';
export default function App() {
const { render, useSubscribe } = useForm({ name: 'name', age: 'age' });
const renderName = render('name')(<input className="input" />);
const renderAge = render('age')(<input className="input" />);
const subscribemodel = useSubscribe(({ model }) => model);
const subscribeAge = useSubscribe(({ model }) => model.age);
return (
<>
{renderName}
{renderAge}
最新值: { JSON.stringify(subscribemodel) } { subscribeAge }
</>
);
}
我们设计了订阅值的API,在实际项目开发中无需手动使用state 中间变量结合onChange 去订阅。
watch
js
import React from 'react';
import { useForm } from 'react-form-simple';
export default function App() {
const { render, useWatch } = useForm({ name: 'name', age: 'age' });
const renderName = render('name')(<input className="input" />);
const renderAge = render('age')(<input className="input" />);
useWatch(
({ model }) => [model.name, model.age],
(value, preValue) => {
console.log({ value, preValue });
},
);
return (
<>
{renderName}
{renderAge}
</>
);
}
我们设计了观察表单模型数据是否更改的API,开发人员可以基于此做一些更加复杂的逻辑判断。
单元测试
单元测试覆盖率接近为100%。
社区
我们建立了一个微信群,如果感兴趣,请加入社区
文档
更多用法,请查看文档
关于我们
感谢您阅读这篇文章!我们团队致力于提供一个轻量级、可扩展且易用的 React 表单库,以便开发者能够更便捷地处理复杂的表单逻辑。我们的目标是为 React 社区提供一个高度可定制的表单解决方案,使开发者能够专注于业务逻辑而不必过多关心表单的状态管理。
如果您对 react-form-simple 有任何疑问、建议或反馈,请随时在我们的社区中与我们联系。我们非常欢迎您的参与,共同推动这个库的发展和改进。
感谢您选择使用 react-form-simple,希望它能在您的项目中发挥出色,并为您的开发工作带来便利。