react-hook-form

在react 16.8的版本中,react推出了hook这一个新特性。在之前的时候,许多需要复用的逻辑我们都是靠使用render props或是hoc来解决的,但hook的推出,给予了我们新的方式去复用逻辑,这个方式更灵活,使用起来也更加的优雅。可以说hook将改变很多我们惯常书写组件的形式和思路,它更加的函数化,也更加的灵活。
当我们用最基本的class组件去写表单的时候,我们往往需要去创建多个state,和改变state的函数。这些代码往往重复度高,复用性也不强。而有了hook我们就有了新的解决方法。
首先是抽取表单中input的逻辑,包括最为通用的onchange,以及验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const useInput = (name, initValue, rules) => {
const [value, setValue] = useState(initValue);
const [error, setError] = useState(false);
const onChange = function(event) {
setError(false)
setValue(event.currentTarget.value);
};
const onBlur = function(event) {
validate()
};
const validate = function(){
let error = false
if(rules.required && value === ''){
error = rules.required
}
if(rules.validate && !error){
const hasError = rules.validate(value)
error = hasError
}
if(error){
setError(error)
}
return error;
}

return {
props: {
name,
value,
onChange,
onBlur,
className: (error? 'has-error': ''),
},
validate,
error
}
}

这里其实就是一个自定义的hook,有了这个hook,我们就可以通过

1
2
const name = useInput('name', 'test-name', {required: '请填写姓名’})
<input {...name.props}/>

来得到一个input,这个input有一个默认值,和对应的验证条件,如果不符合条件,会在input上添加一个”has-error”的class。
但一个表单肯定不会只有一个input,要考虑到多个input的验证和最后数据的收集和提交,我们可以再自定义一个hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const useHandleFrom = (inputs, submit) => {
const [errorTip, setErrorTip] = useState(null);
function handleSubmit() {
setErrorTip(null)
const hasError = inputs.filter(input => {
return !!input.validate();
});
if (hasError.length) {
setErrorTip(hasError[0].error);
return;
}
const formValue = inputs.map(item => {
return { name: item.props.name, value: item.props.value };
});
submit(formValue);
}
return { handleSubmit, errorTip };
};

这个hook会传出一个包装好的提交数据的函数,以及应该去显示的错误提示。在这个函数中,我们会去遍历传入的对象的校验函数,看有没有错误。如果没有,则会执行传入回调。一般这个回调里应该就是提交表单的对应代码了。
最后是对应的表单组件的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const EnhancedFrom = props => {
const name = useInput("name", "test-name", { required: "请填写姓名" });
const phone = useInput("phone", "123456789", {
required: "请填写电话",
validate: value => {
if (!/\d{9}$/.test(value)) {
return "电话不符合格式";
}
return null;
}
});
const submitData = value => {
console.log(value);
};
const { handleSubmit: submit, errorTip } = useHandleFrom(
[name, phone],
submitData
);
return (
<div>
<input {...name.props} />
<input {...phone.props} />
<button onClick={submit}>提交</button>
<span style={{ color: "red" }}>{errorTip}</span>
</div>
);
};

其实可以看到,在上面的两个自定义hook,一个只是抽出了input的改变值和验证的逻辑,一个只是抽出了表单的验证和提交的逻辑。这两个hook完完全全可以分开来用,而且useInput其实也不仅仅适用于input,经过一些小小的改动,我们可以让这个函数适用于其他的组件。
在慢慢踩坑hook的时候,我清晰的感觉到hook肯定会慢慢的开始改变我们书写react的观念与方式。希望这篇文章也能对别人理解hook提供一些小小的帮助。
关于hook还有一些不错的资料:
link