如何优雅的处理 React 表单
HTML 表单处理本身是一件比较简单的事情,但是当我们对交互的要求高了之后,他就会变得异常复杂——尤其是在 React 中使用时,我们不得不创建冗长的代码去维护各种状态。
那么有没有什么现成的开源方案可以供我们使用,最终优雅的创建 React 表单呢?
本文不会详细阐述每个库的用法、api,只是向大家介绍整合方案
如果我们直接写代码,大概率表单组件最后会是这样:
const [inputVal, setInputVal] = useState("");
const [errMessage, setErrMessage] = useState(null);
const isError = useMemo(() => Boolean(errMessage), [errMessage]);
function validate(val) {
if (!val) {
return "xxxx";
}
if (val.length > 10) {
return "xxxx";
}
if (val.length < 2) {
return "xxx";
}
return null;
}
function handleChange(e) {
const value = e.target.value;
setInputVal(value);
const errMsg = validate(value);
setErrMessage(errMsg);
}
return (
<div>
<input onChange={handleChange} />
{isError && <p>{errMessage}</p>}
</div>
);
我们仅仅只是校验了一个变量的长度和存在,就已经用了这么多的代码,还要处理三个状态!这太反人类了。
因此我们可以尝试使用如下四个库:react-hook-form
, @hookform/resolvers
, joi
, joi-messages-zh_cn
。
优雅的表单处理
react-hook-form 可以非常方便的为我们创建一个表单,拥有更少的代码、更好的性能,并且可以配合所有的第三方库。
import { useForm } from "react-hook-form";
export default function App() {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm();
const onSubmit = (data) => console.log(data);
console.log(watch("example"));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input defaultValue="test" {...register("example")} />
<input {...register("exampleRequired", { required: true })} />
{errors.exampleRequired && <span>This field is required</span>}
<input type="submit" />
</form>
);
}
配合 Material-UI:
import Select from "react-select";
import { useForm, Controller } from "react-hook-form";
import Input from "@material-ui/core/Input";
const App = () => {
const { control, handleSubmit } = useForm({
defaultValues: {
firstName: "",
select: {},
},
});
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="firstName"
control={control}
render={({ field }) => <Input {...field} />}
/>
<Controller
name="select"
control={control}
render={({ field }) => (
<Select
{...field}
options={[
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
]}
/>
)}
/>
<input type="submit" />
</form>
);
};
优雅的校验
joi
是一个用来校验 JavaScript 类型的库。
我们可以定义一个 Schema:
const schema = Joi.object({
username: Joi.string().max(12).min(2).required(),
password: Joi.string().min(6).required(),
});
通过 @hookform/resolvers
库我们可以将 schema 传递给 react-hook-form
用来校验表单数据。
但现在有一个问题,那就是所有的报错都是英文,该如何切换为中文呢?
这就需要用到 Joi 的 defaults
方法了。
// my_joi.js
import Joi from "joi";
import cnMessages from "joi-messages-zh_cn";
export default Joi.defaults((schema) =>
schema.options({
messages: { ...cnMessages["zh-cn"] },
})
);
messages 是我们的自定义消息,joi-message-zh_cn 这个库已经为我们写好了中文的报错消息。
最后,在定义 scheme 时,加上 .label('用户名')
,就可以讲报错消息彻底改换为中文了。
最终效果
这里放一段使用 material ui 的例子:
// 这里使用 defaults 封装过的 Joi
const schema = Joi.object({
username: Joi.string().max(12).min(2).required().label("用户名"),
password: Joi.string().min(6).required().label("密码"),
});
function LoginForm({ onSubmit }) {
const {
control,
handleSubmit,
register,
formState: { errors },
} = useForm({
defaultValues: {
username: "",
password: "",
},
resolver: joiResolver(schema),
});
function formError(field) {
const err = errors[field];
return {
error: Boolean(err),
helperText: err?.message,
};
}
return (
<form onSubmit={handleSubmit(onSubmit)} className={styles.wrapper}>
<Controller
name="username"
control={control}
render={({ field }) => (
<TextField
{...field}
{...register("username")}
className={styles.item}
variant="standard"
label="用户名"
required
{...formError("username")}
/>
)}
/>
<Controller
name="password"
control={control}
render={({ field }) => (
<TextField
{...field}
{...register("password")}
className={styles.item}
variant="standard"
type="password"
label="密码"
required
{...formError("password")}
/>
)}
/>
<Button type="submit">提交</Button>
</form>
);
}
标签:const,import,return,优雅,React,joi,Joi,表单
From: https://www.cnblogs.com/xhyccc/p/17400318.html