react-hook-form通过ref改值后触发MUI TextField重渲染的方法
问题场景
- 使用 Material UI 的
TextField组件搭配react-hook-form实现表单控制,表单初始传入的defaultValues为空 - 页面加载后发起API请求获取用户账户数据,表单初始渲染完成后,
defaultValues会随接口返回数据更新 - 表单逻辑中使用
useEffect钩子,在接收到新的填充数据(包括接口返回初始数据、后续数据刷新场景)时调用reset()方法重置表单值 - 异常表现:上述逻辑在多数场景运行正常,但当初始
defaultValues为空时会出现样式异常:表单值虽然被正确填入输入框,但输入框标签不会上浮到边框位置,占位符也不会消失,只有手动编辑字段后标签样式才会恢复正常
问题根因
react-hook-form 默认通过 ref 直接操作DOM设置输入框值,这个过程不会触发 MUI TextField 组件的React重渲染,导致组件无法识别输入框已有值,无法自动调整标签浮动状态。
修复方案
最稳妥的方案是使用 react-hook-form 官方提供的 Controller 组件包裹 TextField,将字段转为受控模式,让表单值通过props传递给组件,值变化时自然触发组件重渲染,MUI就能正确识别值状态更新样式。
修复步骤
- 从
react-hook-form中额外导入Controller,并在useForm返回值中解构出control属性 - 替换原来直接通过
register绑定字段的写法,用Controller包裹TextField,通过render属性把表单字段的属性透传给组件
修复后的核心代码如下:
import React, { useEffect } from 'react' import { useForm, Controller } from 'react-hook-form' import * as Yup from 'yup' import { yupResolver } from '@hookform/resolvers/yup' import Button from '@material-ui/core/Button' import BaseTextField from '@material-ui/core/TextField' const schema = Yup.object().shape({ firstName: Yup.string(), }) const TextField = React.forwardRef((props, ref) => ( <BaseTextField {...props} inputRef={ref} /> )) const MyForm = ({ data, mutate, submitting }) => { // 额外解构出control const { control, handleSubmit, reset } = useForm({ defaultValues: data, resolver: schema ? yupResolver(schema) : undefined, }) useEffect(() => { reset(data) }, [reset, data]) return ( <form onSubmit={handleSubmit(mutate)}> {/* 使用Controller包裹字段 */} <Controller name="firstName" control={control} render={({ field }) => ( <TextField {...field} disabled={submitting} fullWidth id="firstName" label="First Name" margin="normal" variant="outlined" /> )} /> <Button variant="contained" disabled={submitting} color="primary" type="submit" > Save </Button> </form> ) }
调整后reset()更新表单值时,值会通过props传递给TextField,组件能正确感知值的变化,自动触发标签上浮的样式逻辑,不会再出现样式错位问题。这也是react-hook-form官方推荐的对接第三方UI组件库的标准方式。
内容的提问来源于stack exchange,提问作者thclark
相关产品推荐
相关产品推荐

