admin管理员组

文章数量:1023195

I'm using the bination of MUI + React Hook Form, so I've created a CustomTextField.tsx ponent 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: =/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?

I'm using the bination of MUI + React Hook Form, so I've created a CustomTextField.tsx ponent 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?

Share Improve this question asked Oct 2, 2022 at 16:21 TobyToby 1191 silver badge9 bronze badges 2
  • I don't see an onChange event for your implementation, you need the onChange event to change the state so that it can be updated. – shinanl Commented Oct 2, 2022 at 19:11
  • I have to pass the onChange from Controller to TextField instead, so the React Hook Form works. I don't know how I can use onChange both parent level, and ponent level – Toby Commented Oct 2, 2022 at 19:29
Add a ment  | 

2 Answers 2

Reset to default 2

What you are trying to is have a text input where the user can type a value, but you can also set the value externally by clicking the "Fetch Data" button.

Your setup includes conflicting sources of truth. The value of the field is set to the data state and the value which is stored in the react-hook-form state is ignored.

What you want to do is to modify the internal state of the react-hook-form when the button is pressed.

You can delete the local state:

const [data, setData] = useState<string>("");

Instead, you can use the setValue helper function from the form:

const { control, handleSubmit, setValue } = useForm<FormValues>();

const fetchingData = () => {
  setValue("description", "fetched description Text");
};

In your CustomTextField, make sure that you set the value of the input to the value from the form state.

render={({
  field: { onChange, value },
  fieldState: { error },
  formState
}) => <CusTextField onChange={onChange} value={value} {...props} />}

Complete Code

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/>
  )
}

I'm using the bination of MUI + React Hook Form, so I've created a CustomTextField.tsx ponent 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: =/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?

I'm using the bination of MUI + React Hook Form, so I've created a CustomTextField.tsx ponent 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?

Share Improve this question asked Oct 2, 2022 at 16:21 TobyToby 1191 silver badge9 bronze badges 2
  • I don't see an onChange event for your implementation, you need the onChange event to change the state so that it can be updated. – shinanl Commented Oct 2, 2022 at 19:11
  • I have to pass the onChange from Controller to TextField instead, so the React Hook Form works. I don't know how I can use onChange both parent level, and ponent level – Toby Commented Oct 2, 2022 at 19:29
Add a ment  | 

2 Answers 2

Reset to default 2

What you are trying to is have a text input where the user can type a value, but you can also set the value externally by clicking the "Fetch Data" button.

Your setup includes conflicting sources of truth. The value of the field is set to the data state and the value which is stored in the react-hook-form state is ignored.

What you want to do is to modify the internal state of the react-hook-form when the button is pressed.

You can delete the local state:

const [data, setData] = useState<string>("");

Instead, you can use the setValue helper function from the form:

const { control, handleSubmit, setValue } = useForm<FormValues>();

const fetchingData = () => {
  setValue("description", "fetched description Text");
};

In your CustomTextField, make sure that you set the value of the input to the value from the form state.

render={({
  field: { onChange, value },
  fieldState: { error },
  formState
}) => <CusTextField onChange={onChange} value={value} {...props} />}

Complete Code

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/>
  )
}

本文标签: javascriptMUIReact Hook Form Fill out TextField value but then can39t modify the valueStack Overflow