调用react-hook-form的reset后,如何让Material-UI字段正确渲染?
解决React Hook Form reset后Material-UI TextField渲染异常的问题
问题根源
- 笔误导致number字段初始值错误:number类型的TextField错误使用
INITIAL_VALUES.string作为defaultValue,导致初始渲染时输入框显示与字段类型不匹配的空字符串。 - defaultValue使用方式错误:React Hook Form的
reset方法更新的是表单内部状态,但手动给TextField设置的defaultValue仅在组件首次渲染时生效,后续reset无法同步更新输入框的显示值。
修复步骤
步骤1:修正number字段的defaultValue笔误
将number字段TextField的defaultValue={INITIAL_VALUES.string}改为INITIAL_VALUES.number。
步骤2:将初始值配置到useForm中,移除TextField的defaultValue
在useForm初始化时传入defaultValues参数,替代给每个TextField单独设置defaultValue的方式,确保reset方法能正确同步更新输入框的显示状态。
修改后的完整代码
model.ts(无需修改)
import * as yup from "yup"; import { InferType } from "yup"; export const SCHEMA = yup.object({ string: yup.string().defined().required("Required").max(100, "Too long"), number: yup.number().defined().required("Required").min(1, "Must be positive") }); export type FormValues = InferType<typeof SCHEMA>; export const INITIAL_VALUES: FormValues = { string: "", number: 0 };
表单组件
import { Grid, Box, TextField, Typography, Button } from "@mui/material"; import { useForm } from "react-hook-form"; import { SCHEMA, INITIAL_VALUES, FormValues } from "./model"; import { yupResolver } from "@hookform/resolvers/yup"; import { useEffect, useState } from "react"; export default function EditItemView() { const resolver = yupResolver(SCHEMA); const [isLoading, setLoading] = useState(false); const { register, handleSubmit, reset, formState: { errors } } = useForm<FormValues>({ resolver, mode: "all", defaultValues: INITIAL_VALUES // 将初始值配置到useForm中 }); useEffect(() => { setLoading(true); // 模拟从服务器加载数据 setTimeout(() => { reset({ number: 944, string: "a new string" }); setLoading(false); }, 2000); }, [reset]); // 添加reset到依赖数组,避免 useEffect 依赖警告 return ( <Box padding={2}> <form onSubmit={handleSubmit((formData) => console.log(formData))}> <Grid container direction="column" alignItems="stretch" spacing={2}> <Grid item> <Typography variant="h5">Edit item</Typography> {isLoading && <Typography>Loading...</Typography>} </Grid> <Grid item> <TextField {...register("string")} variant="standard" fullWidth label="Type a string" error={!!errors["string"]} helperText={errors["string"]?.message} /> </Grid> <Grid item> <TextField {...register("number")} variant="standard" fullWidth label="Type a positive number" type="number" // 添加type属性匹配字段类型 error={!!errors["number"]} helperText={errors["number"]?.message} /> </Grid> <Grid item container justifyContent="flex-end"> <Grid> <Button disabled={isLoading} type="submit" variant="contained"> Submit </Button> </Grid> </Grid> </Grid> </form> </Box> ); }
额外优化建议
给number字段的TextField添加type="number"属性,让浏览器提供匹配的数字输入控件,同时减少非数字内容的输入干扰。
内容的提问来源于stack exchange,提问作者acanthite
相关产品推荐
相关产品推荐

