Skip to content
Advertisement

MUI + React Hook Form: Fill out TextField value but then can’t modify the value

I’m using the combination of MUI + React Hook Form, so I’ve created a CustomTextField.tsx component to make it worked.

// CustomTextField.tsx
import { TextField } from "@mui/material";

export default function CustomTextField(props: any) {
  return (
    <Controller
      name={props.name}
      control={props.control}
      render={({
        field: { onChange, value },
        fieldState: { error },
        formState
      }) => <TextField onChange={onChange} {...props} />}
    />
  );
}

Then at the app/parent level, I want to these steps:

  1. Fetch data and display to the TextField.
  2. Modify the text in TextField
  3. Submit the new value in TextField

This is my approach:

//App.tsx
export default function App() {
  const { control, handleSubmit } = useForm();
  const [fetchedData, setFetchedData] = useState<string>("");
  ...
  return (
...
        <CustomTextField
          control={control}
          name="description"
          label="Description"
          type="text"
          variant="outlined"
          value={fetchedData ? fetchedData: ""}     //<-- fetched data is set to value of TextField to display
        />
...
  );
}

With this approach, I managed to display the fetchedData on TextField UI, but can not modify that data on text field. Also when I submit, the data is not correct to what display on the TextField

I have created a codesandbox link for this: https://codesandbox.io/s/blissful-sanne-x858dx?file=/src/App.tsx:190-1155

How can I display the fetchedData, but also can modify the data in text field and then submit through React Hook Form later?

Advertisement

Answer

Inspired by @Linda solution, I’ve came up with this approach, that ensures the functionality working with the style of MUI TextField as well.

The setValue will be passed down to custom TextField to set the value. And to keep the {...props} functionality, I delete the setValue props before spreading it on MUI TextField.

//CustomTextField.tsx
import { TextField } from "@mui/material"
import { Controller } from "react-hook-form"

export default function CustomTextField(props: any) {
  const propsObj = { ...props }
  delete propsObj.setValue
  return (
    <Controller
      name={props.name}
      control={props.control}
      defaultValue={""}
      render={({
        field: { onChange, value },
        fieldState: { error },
        formState,
      }) => (
        <TextField
          value={value}
          onChange={({ target: { value } }) => {
            onChange(value)
            if (props?.setValue) props.setValue(props.name, value)
          }}
          {...propsObj}
        />
      )}
    />
  )
}

//App.tsx
export default function App(){
  const { control, handleSubmit, setValue } = useForm()
  return (
    <form onSubmit={handleSubmit(...)}>
      <CustomTextField
        control={control}
        name="description"
        label="Description"
        type="text"
        variant="outlined"
        setValue={setValue}
      />
    <form/>
  )
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement