[React]监听Form中某个字段的变化
前言
有这样一个需求,整个组件是一个表单,在表单中,如果某一个字段的值发生了变化,那需要根据逻辑关系渲染不同的表单项。
form.getFieldValue()
使用getFieldValue可以获取form表单中的值,于是有了如下代码:
const [form] = Form.useForm();
const input = form.getFieldValue('input');<Form form={form}><Form.Item label="输入值" name="input"><Input /></Form.Item>{input?.length > 0 && <div>输入的值是:{input}</div>}
</Form>;
但是发现一个问题,这里即使input发生了变化,也并不会触发UI更新。简单来说,form.getFieldValue取到的值并不是一个 state。
那是否可以把此处的input字段设置一个state呢?
const [input, setInput] = useState('');<Input onChange={(event) => setInput(event.target.value)} />
那么这里就要保持表单中值和state中input值的同步,必须手动维护二者的关系,如果这种值很多,会造成非常混乱的逻辑,不推荐这样的作法。
Form.useWatch
从 antd@4.20.0 开始,antd Form 添加了一个新的 API Form.useWatch
,用于处理此种情况。
const [form] = Form.useForm();
const inputValue = Form.useWatch('input', form);<Form form={form}><Form.Item label="输入值" name="input"><Input /></Form.Item>{inputValue ?.length > 0 && <div>输入的值是:{inputValue }</div>}
</Form>;
Form.useWatch
其实就是把 inputValue 变为了一个 state,然后内部处理了表单联动。state 的问题就是,它会触发整个组件的 re-render,进行不必要的 diff,如果组件很大而且是监听 Input 实时输入,这种性能消耗是很恐怖的,每次按键都是一次全量 diff。
而这种 re-render 其实毫无意义,因为我们 “精准” 的知道,就是要监听 song 字段的变化,根据 song 的值来更新 “局部” 的 UI,而不是更新整体 UI。
Watch组件
Ant Plus 5(antx)中提供了一个 Watch
组件,专用于监听表单字段变化,并更新局部 UI 的需求。
import { Form, Watch, Input } from 'antx';const [form] = Form.useForm();<Form form={form}><Input label="输入值" name="input" /><Watch name="input">{(inputValue) => {// 仅此处 UI 更新,不会每次输入都触发整个组件 re-renderreturn inputValue?.length > 0 && <div>输入值:{inputValue}</div>;}}</Watch>
</Form>;