Mui TextField placeholder is displayed with value on first refresh

882 Views Asked by At

I'm getting this weird behavior that I don't know how to solve, on edit mode of this form if I refresh the page I get a bug where both the value and the placeholder are displayed in the field

-- This is my form component


const Form = () => {
  // fetch hook to get the settings data.
  const settings = useGetSettingsQuery();
  // initialize the useFormik hook with the data just fetched
  const form = useSettingsForm({ initialValues: settings.data?.data ?? {} });

  return (
    <Box>
      <Grid container spacing={2}>
         <Grid item xs={12}>
          <TextField
            fullWidth
            name={'id'}
            label={'id'}
            placeholder={'ticket id'}
            variant="outlined"
            value={form.values.id}
            onChange={form.handleChange}
          />
        </Grid>
        <Grid item xs={12}>
          initial values
          <pre>{JSON.stringify({ id: form.initialValues.id }, null, 2)}</pre>
        </Grid>
        <Grid item xs={12}>
          current value values
          <pre>{JSON.stringify({ id: form.values.id }, null, 2)}</pre>
        </Grid>
      </Grid>
    </Box>
  );
};

-- and this is my hook, right now I've deleted everything in my hook, and this is what's left:

export const useSettingsForm = ({ initialValues }: Props) => {
  return useFormik<Partial<ISetting>>({
    enableReinitialize: true,
    initialValues: {
      ...initialValues,
    },
    validationSchema: Yup.object().shape({}),
    onSubmit: async (values) => {
      console.log('submitted -> ', values);
    },
  });
};

the current behavior

enter image description here


For my useGetSettings hook, I'm using RTK query to fetch the data and handle the server state, this is the a snippet of apiSlice:

export const settingApiSlice = apiSlice.injectEndpoints({
  endpoints(builder) {
    return {
      getSettings: builder.query<IGetSettingsResp, void>({
        query() {
          return `/setting`;
        },
        providesTags: ['setting'],
      }),
    };
  },
});

export const { useGetSettingsQuery } = settingApiSlice;


as you can see in the picture the placeholder text and value are displayed, is there any way to fix this bug, thank you

2

There are 2 best solutions below

0
Wesley LeMahieu On

In Formik, the name of the input ties into the property of it's value inside of form.values. So this:

<TextField
  fullWidth
  name={'ticket number'}
  label={'ticket number'}
  placeholder={'ticket number'}
  variant="outlined"
  value={form.values.id}
  onChange={form.handleChange}
/>

Should be this:

<TextField
  fullWidth
  name="id"
  label={'ticket number'}
  placeholder={'ticket number'}
  variant="outlined"
  value={form.values.id}
  onChange={form.handleChange}
/>

When you use name={'ticket number'} (or name="ticket number"), it's literally trying to set the value on form.values.ticket number instead of form.values.id, as you want it to be since that's your value.

The id in value={form.values.id} is connected to name="id".

0
emirhan demir On

Adding a defaultValue will solve the problem, at least it solved in my case.

<Grid item xs={12}>
                    <TextField
                        fullWidth
                        value={salary}
                        label= "Blah Blah Blah..."
                        variant="outlined"
                        type="number"
                        inputProps={{ min: 0 }}
                        onChange={(e) => setSalary(parseInt(e.target.value, 10))}
                        required
                    />
                </Grid>

This is my code and it's output looks like this:

When I add the defaultValue={0} part, the code look like this: enter image description here

I am a newbie in React field and therefore, following explanation is totaly my own idea, I literally think this way but I am not sure if it's true. I assume this problem is caused because the React tries to load the Texfield and it fails loading the value since the value hasn't been loaded into the state and the label is loaded into where it normally belongs (inside the text field) but If you provide a defaultValue, it will display the label as it should (on the top of the text field).