Search code examples
reactjsformsmaterial-uireact-hook-formreact-forms

React Hook Form - Value property got disappeared while state is dirty


I am using react-hook-form for managing form states. But when I start typing in a text field the value property shown in devtool disappeared.

UI initial state. enter image description here

As shown in the above screenshot, value is null or empty string. Now when I starts typing, the value property disappeared from the devtool. enter image description here

Here is the login screen code.

import React from "react";
import { useForm } from "react-hook-form";
import { MuiTypography } from "../../components/mui/typography/Typography";
import { MuiStack } from "../../components/mui/layouts/Stack";
import { MuiBox } from "../../components/mui/layouts/Box";
import { MuiPaper } from "../../components/mui/layouts/Paper";
import { MuiAvatar } from "../../components/mui/data-display/Avatar";
import { MuiTextField } from "../../components/mui/form-controls/TextField";
import { MuiButton } from "../../components/mui/form-controls/Button";
import { DevTool } from "@hookform/devtools";

export const Login = () => {
  const {
    handleSubmit,
    register,
    formState: { errors },
    control,
  } = useForm({
    defaultValues: {
      email: "",
      password: "",
    },
  });

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <MuiStack align="center" mt={2}>
      <MuiTypography component={"h1"} variant={"h4"} text={"Security Login"} />
      <form onSubmit={handleSubmit(onSubmit)} noValidate>
        <MuiPaper m={2} p={2} sx={{width: "400px"}} elevation={5}>
          <MuiStack mt={2} p={2} >
            <MuiBox flex={1} direction={"row"}>
              <MuiAvatar src={require("./assets/logo.png")} height={100} width={100}/>
            </MuiBox>
            <MuiTextField
              label={"Email"}
              type={"text"}
              {...register("email", { required: "Email is required" })}
              error={!!errors.email}
              helperText={errors.email?.message}
            />
            <MuiTextField
              label="Password"
              type="password"
              {...register("password", { required: "Password is required" })}
              error={!!errors.password}
              helperText={errors.password?.message}
            />
            <MuiButton
              type={"submit"}
              variant="contained"
              color="primary"
              text="Login"
            />
          </MuiStack>
        </MuiPaper>
      </form>
      <DevTool control={control} />
    </MuiStack>
  );
};

You might need MuiTextField component code as well. So here it is.

import { TextField } from '@mui/material'

export const MuiTextField = ({
  label,
  type,
  error,
  helperText,
  variant = "outlined",
  color = "primary",
  size = "small",
  // inputProps,
  // value,
  // handleChange,
  ...rest
}) => {
  return (
    <TextField
      label={label}
      type={type}
      error={error}
      helperText={helperText}
      variant={variant}
      color={color}
      size={size}
      // inputProps={inputProps}
      // value={value}
      // onChange={handleChange}
      {...rest}
    />
  );
};

I have commented following props just to confirm if these are conflicting but still the same behaviour.

  • inputProps={inputProps}
  • value={value}
  • onChange={handleChange}

Note: If I use Textfield directly from MUI I get the expected behaviour. But using a custom component is requirement. :)


Solution

  • The issue was due to the missing reference we need to pass. Once I added forwardRef hook implementation in custom component, I got the expected result.

    Here is the updated component.

    export const MuiTextField = React.forwardRef(
      (
        {
          label,
          type,
          error,
          helperText,
          variant = "outlined",
          color = "primary",
          size = "small",
          inputProps,
          value,
          handleChange,
          ...rest
        },
        ref
      ) => (
        <TextField
          label={label}
          type={type}
          error={error}
          helperText={helperText}
          variant={variant}
          color={color}
          size={size}
          ref={ref}
          inputProps={inputProps}
          value={value}
          onChange={handleChange}
          {...rest}
        />
      )
    );