React Hook Form中Redux返回Null引发的非受控输入转受控错误
问题解决思路
出现「非受控输入转为受控」错误的核心原因是:组件初始化时,defaultValues里的字段值为undefined(因为data初始为null,data?.firstName返回undefined),此时react-hook-form会将输入视为非受控组件;当Redux数据加载完成后调用reset传入有效值,输入组件从非受控转为受控,触发报错。
具体修复步骤:
- 初始化defaultValues为受控状态:给所有表单字段设置初始空字符串,确保组件一开始就是受控模式,避免后续状态切换。
- 条件触发reset:只有当
data存在(即Redux数据加载完成)时才调用reset,避免在data为null时重置出undefined值。 - 修正字段名不一致问题:Discard按钮里的
data?.first_name要改为data?.firstName,和表单字段名保持一致。
修改后的完整代码:
// ** React Imports import { useEffect, Fragment } from "react"; // ** Third Party Components import { useForm, Controller } from "react-hook-form"; // ** Reactstrap Imports import { Row, Col, Form, Card, Input, Label, Button, CardBody, CardTitle, CardHeader, FormFeedback, } from "reactstrap"; // ** Store & Actions import { useDispatch, useSelector } from "react-redux"; import { getUserProfile } from "@store/userProfile"; const UserProfile = () => { // ** Store Vars const dispatch = useDispatch(); const { data } = useSelector((state) => state.userProfile); //** ComponentDidMount useEffect(() => { dispatch(getUserProfile()); }, [dispatch]); // ** Hooks // 初始化空字符串,确保表单一开始就是受控状态 const defaultValues = { firstName: '', lastName: '', email: '', }; const { control, setValue, setError, handleSubmit, reset, formState: { errors }, } = useForm({ defaultValues, }); //** 仅当data存在时执行reset useEffect(() => { if (data) { reset({ firstName: data.firstName, lastName: data.lastName, email: data.email, }); } }, [data, reset]); // 补充onSubmit函数(原代码遗漏) const onSubmit = (formData) => { // 处理表单提交逻辑 console.log(formData); }; return ( <Fragment> <Card> <CardHeader className="border-bottom py-2"> <CardTitle tag="h4">User Account</CardTitle> </CardHeader> <CardBody className="py-2 my-25"> <Form className="mt-2 pt-50" onSubmit={handleSubmit(onSubmit)}> <Row> <Col sm="6" className="mb-1"> <Label className="form-label" for="firstName"> First Name </Label> <Controller name="firstName" control={control} render={({ field }) => ( <Input id="firstName" placeholder="John" invalid={!!errors.firstName} {...field} /> )} /> {errors.firstName && ( <FormFeedback>Please enter a valid First Name</FormFeedback> )} </Col> <Col sm="6" className="mb-1"> <Label className="form-label" for="lastName"> Last Name </Label> <Controller name="lastName" control={control} render={({ field }) => ( <Input id="lastName" placeholder="Doe" invalid={!!errors.lastName} {...field} /> )} /> {errors.lastName && ( <FormFeedback>Please enter a valid Last Name</FormFeedback> )} </Col> <Col sm="6" className="mb-1"> <Label className="form-label" for="login-email"> Email </Label> <Controller id="email" name="email" control={control} render={({ field }) => ( <Input type="email" placeholder="john@example.com" invalid={!!errors.email} {...field} /> )} /> {errors.email && ( <FormFeedback>{errors.email.message}</FormFeedback> )} </Col> <Col className="mt-2" sm="12"> <Button type="submit" className="me-1" color="primary"> Save changes </Button> <Button color="secondary" outline onClick={() => { // 修正字段名,和data里的key保持一致 if (data) { setValue("firstName", data.firstName); setValue("lastName", data.lastName); setValue("email", data.email); } }} > Discard </Button> </Col> </Row> </Form> </CardBody> </Card> </Fragment> ); }; export default UserProfile;
额外说明:
- 原代码中遗漏了
onSubmit函数,已补充完整,否则表单提交会报错。 - 将
errors.firstName && true简化为!!errors.firstName,逻辑更清晰。
内容的提问来源于stack exchange,提问作者Frank HAWK
相关产品推荐
相关产品推荐

