function MyForm() {
const [value, setValue] = useState('')
const handleChange = (evt) => {
setValue(evt.target.value)
}
return <input value={value} onChange={this.handleChange} />
}
受控组件,一个表单组件的状态完全由React管控,但是频繁的更新状态,可能会产生性能问题
function MyForm() {
const inputRef = useRef()
const handleSubmit = (evt) => {
// 使用prevetnDefault防止页面被刷新
evt.preventDefault()
alert(inputRef.current.value)
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input ref={inputRef} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
非受控组件,表单元素的值不是由父组件决定的,而是完全内部的状态。
可以看到,通过非受控组件的方式,input的输入过程对整个组件状态没有任何影响,自然也不会导致组件的重新渲染。
之前,对于受控组件,遵循下面两个步骤:
即,维护表单组件的状态逻辑,核心在于三个部分:
既然对于每个表单元素的处理逻辑都是一样的,我们可以用hooks来实现逻辑的复用
const useForm = (initialValues = {}) => {
// 设置整个form的状态values
const [values, setValues] = useState(initialValues)
const setFieldValue = useCallback((name,value) => {
setValues((value) => return {
...values,
[name]: value
})
}, [])
return { values, setFieldValue }
}
使用时:
// ...
const [values, setFieldValues] = useForm()
// ...
<input value={values.name || null} onChange={setFieldValues('name',evt.target.value)} />
<input value={values.email || null} onChange={setFieldValues('email', evt.target.value)} />
基本上一些开源的表单方案都是基于这么一个核心的原理:把表单的状态管理单独提取出来,成为一个可重用的Hook。
同样遵循状态驱动这个原则:
下面,为已有的useForm这个Hook增加验证的API接口:
// 提供一个validators对象提供针对某个字段的验证函数
const useForm = (initialValues = {}, validators) => {
const [values,setValues] = useState(initialValues)
// 定义了 errors 状态
const [errors, setErrors] = useState({})
const setFieldValue = useCallback((name, value) => {
setValues(({
...values,
[name]: value
}))
// 调用验证函数验证用户输入
if (validators[name]) {
const errMsg = validators[name](value)
setErrors((errors) => ({
...errors,
[name]: errMsg || null
}))
}
},[validators])
return { values, errors, setFieldValue }
}