做seo网站公司,电影网站怎么建设,logo制作在线,dede汽车资讯网站源码场景
子组件中#xff0c;某一个表格的数据需要依赖于上级组件的某一个表单元素值进行计算。
毫无疑问#xff0c;首先想到的肯定是监听 form 表单中元素的值#xff0c;使用 useEffect 监听表单的变化#xff0c;当值发生变化时#xff0c;重新计算渲染。
首先说下我的…场景
子组件中某一个表格的数据需要依赖于上级组件的某一个表单元素值进行计算。
毫无疑问首先想到的肯定是监听 form 表单中元素的值使用 useEffect 监听表单的变化当值发生变化时重新计算渲染。
首先说下我的代码结构
Form 表单是一个子组件表格组件也是一个子组件且是比较深的子组件包含在tab标签页下。如果说 Form子组件是一级子组件那么表格组件就是一个四级子组件。
在这种多层嵌套下如何把 form 数据传递给对应的表格子组件
毫无疑问选择使用useContext
在顶层组件中通过 Form.useForm() 定义 Form 实例管理数据状态通过 context.Provider value{}/context.Provider传递表单子组件和表格子组件都可进行接收。
不过在子组件监听代码写好后却发现了一个比较尴尬的问题表单元素的值发生了改变但子组件的useEffect 却没能监听到。
// 子组件
import React, { useContext } from react
import context from xxx/xxxconst { form } useContextany(context)useEffect(() {console.log(监听到了变化)// 下面是具体的逻辑
}, [form.getFiledValue(xx)])
注意
当时令我困惑的是当 Form 表单组件的某个表单元素值改变时虽然子组件 useEffect 没有监听到变化但通过表格子组件的输入框的 onBlur 事件调用 form.getFiledValue(xx)却可以拿到最新的值。
分析
需求终归还是要往下开发的监听不了那就想办法监听
在项目中我是使用了 const [form] Form.useForm(); 来创建 Form 实例管理表单数据状态这也是函数式组件推荐的一种方式。
通过使用 useForm 会让表单成为 非受控组件不用通过 useState 创建state 来维护数据。
而且 ant 官网 里面也说了使用这种方式与其他获取数据的方式的区别 Form 仅会对变更的 Field 进行刷新从而避免完整的组件刷新可能引发的性能问题因而无法在 render 阶段通过 form.getFieldsValue 来实时获取字段值。 看到这里其实已经很清楚了因为 使用了 useForm导致表单变成了 非受控组件不能通过 useState 来创建 state 维护数据只能通过 form.getFieldsValue() / form.setFieldsValue() 来获取及设置表单数据ant design 官方文档也有介绍。所以在这种情况下 使用 useEffect 监听不到 form 表单的变化。 换句话说form.getFieldValue(xxx); 并不是响应式的由其取到的值并不会触发 UI 更新即它不是一个 state。
不过可能有人会问我之前也使用过 useEffect 来监听 form.getFieldValue(‘xxx’)UI也能正常渲染啊你这里是不是说错了
答 没有说错我自己之前也有这样的疑问也遇到过这类问题。 在实际项目中一个 react 组件的 re-render 次数是不可控的 特别是代码写的不那么规范的时候所以当看到 UI 更新的时候或许是在新的 re-render 中被连带着更新了又或许是项目代码中 Form组件既使用了 form {form} 属性又使用了 initialValues 属性。如下所示
//
const [form] Form.useForm();Form initialValues{formData} form{form} ref{formRef} /Form解决方案
方案1
ant design 4.20 版本推出了一个新特性Form.useWatch可以直接获取 form 中字段对应的值应该是可以监听到的具体用法可以参考官网这里不多做赘述。
可是 4.2 版本后才支持我的项目版本是 4.12.3暂不支持这个hooks部门领导也不让进行 ant 升级所以就没有尝试这种写法。
而且使用这种方法固然可以监听到不过性能不是太好不建议使用。因为它会触发整个组件的 re-render当组件比较大且监听 input 实时输入时性能消耗就很恐怖。
方案2
拒绝使用 Form.useForm()使用 initialValues 属性是表单变成一个可控组件拥有 state就可以正常监听。
不过对于我的项目代码来说改动量太大不划算。
方案3
使用 useState 额外定义个 state 当表单元素值发生变化时使用 setState()然后将其值通过 context.Provider传递在子组件监听。
方案4
使用 useReducer
useReducer 与 useState 都是用来存储和更新 state相当于 useState 的升级版。
当 type 数量较多时建议使用 useReducer
方案5
Ant Plus 5 的 Watch 组件
专门用于监听表单字段变化并更新局部UI。没尝试过
总结
其实核心要点就一句话Form 内置方法不是响应式的即不是一个state由其设置或者获取的值不会触发UI更新只能对变更的field进行刷新。想要对其进行监听也很简单将其变成一个state即可。