如何在最新的6版本中使用formik实现mui Timepicker?

huangapple go评论77阅读模式
英文:

How to implement mui Timepicker with latest 6 version with formik

问题

我正在使用 MUI react Timepicker
我想要使用 Formik 进行集成,并进行验证,但问题是表单的 initialValues 中没有绑定值。

const [initialValues, setInitialValues] = useState({
  mondayFrom: "",
  mondayTo: "",
});
const onSubmit = async (values: RegisterFormProps) => {
  console.log({values})// 这里没有获得 mondayFrom: ""
}

<Formik initialValues={initialValues} enableReinitialize onSubmit={onSubmit}>
  {({
    values,
    errors,
    touched,
    handleSubmit,
    handleChange,
    isSubmitting,
    setFieldValue,
  }) => (
    <Form onSubmit={handleSubmit}>
      <Field name="mondayFrom">
        {(field) => (
          <TimePicker
            {...field}
            ampm={false}
            format="HH:mm"
            slotProps={{
              textField: {
                label: "Monday From",
                size: "small",
                fullWidth: true,
              },
            }}
          />
        )}
      </Field>
    </Form>
  )}
</Formik>;
英文:

I am working with MUI react Timepicker.
And I want to integrate it using Formik with validation but the issue is the values are not getting bound in the initialValues of the form.

const [initialValues, setInitialValues] = useState({
  mondayFrom: &quot;&quot;,
  mondayTo: &quot;&quot;,
});
const onSubmit = async (values: RegisterFormProps) =&gt; {
  console.log({values})//here not getting mondayFrom: &quot;&quot;
}

    &lt;Formik initialValues={initialValues} enableReinitialize onSubmit={onSubmit}&gt;
  {({
    values,
    errors,
    touched,
    handleSubmit,
    handleChange,
    isSubmitting,
    setFieldValue,
  }) =&gt; (
    &lt;Form onSubmit={handleSubmit}&gt;
      &lt;Field name=&quot;mondayFrom&quot;&gt;
        {(field) =&gt; (
          &lt;TimePicker
            {...field}
            ampm={false}
            format=&quot;HH:mm&quot;
            slotProps={{
              textField: {
                label: &quot;Monday From&quot;,
                size: &quot;small&quot;,
                fullWidth: true,
              },
            }}
          /&gt;
        )}
      &lt;/Field&gt;
    &lt;/Form&gt;
  )}
&lt;/Formik&gt;;

答案1

得分: 2

你的代码几乎正确,但存在两个问题。

  1. 解构字段。
  2. 存在一个已知问题,其中指出

> DateTime选择器未设置与初始值相同类型的数据。DateTime选择器发送包含完整字符串格式的日期时间的属性的对象。

通过将onChange添加到fieldonChange属性来解决此问题。下面的代码与你的代码非常相似,只需应用这些修复。

function App() {
    const [initialValues, setInitialValues] = useState({
        mondayFrom: "",
        mondayTo: "",
    });

    const onSubmit = async (values: RegisterFormProps) => {
        console.log({ values }) // 这里没有获得mondayFrom: ""
        console.log(initialValues);
    }

    return (
        <LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale="en">
            <div style={{ margin: 20, padding: 20 }}>
                <Formik initialValues={initialValues} onSubmit={onSubmit}>
                    {({
                        handleSubmit, values, errors, touched, handleChange, isSubmitting, setFieldValue,
                    }) => (
                        <Form onSubmit={handleSubmit}>
                            <Field name="mondayFrom">
                                {({ field }) => {
                                    return (
                                        <TimePicker
                                            ampm={false}
                                            format="HH:mm"
                                            slotProps={{
                                                textField: {
                                                    label: "Monday From",
                                                    size: "small",
                                                    fullWidth: true,
                                                },
                                            }}
                                            {...field}
                                            onChange={(value) => {
                                                setInitialValues({ mondayTo: initialValues.mondayTo, mondayFrom: value.toString() });
                                            }}
                                        />
                                    );
                                }}
                            </Field>
                        </Form>
                    )}
                </Formik>
            </div>
        </LocalizationProvider>
    );
}

更新:
正如Profer在评论中指出的,更好的onChange方式是:

onChange={(value) => setFieldValue('mondayFrom', value.format("hh:mm"))}
英文:

Your code is almost correct, but there are two issues.

  1. Destructuring field.
  2. There's an open issue bug which states

> the DateTime picker doesn't set the same type of data as in the
> initialValues. DateTime picker sends an object containing a property
> which is the date time in full string format.

onChange is added to overcome that bug by overriding field's onChange property.<br>
This code, very similar to your code just apply those fixes.<br>

function App() {
const [initialValues, setInitialValues] = useState({
mondayFrom: &quot;&quot;, mondayTo: &quot;&quot;,
});
const onSubmit = async (values: RegisterFormProps) =&gt; {
console.log({values})//here not getting mondayFrom: &quot;&quot;
console.log(initialValues)
}
return (&lt;LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale=&quot;en&quot;&gt;
&lt;div style={{margin: 20, padding: 20}}&gt;
&lt;Formik initialValues={initialValues} onSubmit={onSubmit}&gt;
{({
handleSubmit,values, errors, touched, handleChange, isSubmitting, setFieldValue,
}) =&gt; (&lt;Form onSubmit={handleSubmit}&gt;
&lt;Field name=&quot;mondayFrom&quot;&gt;
{({field}) =&gt; {
return (&lt;TimePicker
ampm={false}
format=&quot;HH:mm&quot;
slotProps={{
textField: {
label: &quot;Monday From&quot;, size: &quot;small&quot;, fullWidth: true,
},
}}
{...field}
onChange={(value)=&gt; {
setInitialValues({mondayTo: initialValues.mondayTo,mondayFrom: value.toString()})
}}
/&gt;)}
}
&lt;/Field&gt;
&lt;/Form&gt;)}
&lt;/Formik&gt;
&lt;/div&gt;
&lt;/LocalizationProvider&gt;);
}

Update:<br>
As pointed out by Profer in comments, a better way for onChange is

onChange={(value) =&gt; setFieldValue(&#39;mondayFrom&#39;, value.format(&quot;hh:mm&quot;))}

答案2

得分: 0

你还应该在TimePicker上包括onChange,这样每次更改它时,都会将新值设置为表单值:

<Formik
 initialValues={initialValues}
 enableReinitialize
 onSubmit={onSubmit}>
   {({ handleSubmit }) => (
      <Form onSubmit={handleSubmit}>
         <Field name="mondayFrom">
            {({ field, form }) => (
               <TimePicker
                  {...field}
                  ampm={false}
                  format="HH:mm"
                  slotProps={{
                    textField: {
                      label: "Monday From",
                      size: "small",
                      fullWidth: true
                    }
                  }}
                  onChange={(value) => {
                    form.setFieldValue(field.name, value);
                  }}
                />
              )}
         </Field>
      </Form>
   )}
</Formik>

这里有一个代码示例链接

  • 在示例中,我使用dayjs作为dateadapter
英文:

You should also include onChange to the TimePicker, so every time you change it, you set the new value to form values:

&lt;Formik
 initialValues={initialValues}
 enableReinitialize
 onSubmit={onSubmit} &gt;
   {({ handleSubmit }) =&gt; (
      &lt;Form onSubmit={handleSubmit}&gt;
         &lt;Field name=&quot;mondayFrom&quot;&gt;
            {({ field, form }) =&gt; (
               &lt;TimePicker
                  {...field}
                  ampm={false}
                  format=&quot;HH:mm&quot;
                  slotProps={{
                    textField: {
                      label: &quot;Monday From&quot;,
                      size: &quot;small&quot;,
                      fullWidth: true
                    }
                  }}
                  onChange={(value) =&gt; {
                    form.setFieldValue(field.name, value);
                  }}
                /&gt;
              )}
         &lt;/Field&gt;
      &lt;/Form&gt;
   )}
&lt;/Formik&gt;

Here´s a code sample link.

* i'm using dayjs as dateadapter in the example.

答案3

得分: 0

以下是您要翻译的部分:

问题描述

问题在于,您正在使用的组件(TimePicker)与其他组件的行为略有不同。

Formik 和 onChange 处理程序

Formik,您可能知道,使在 React 中开发表单变得更加容易。它通过维护所有输入组件的内部状态并在用户在input组件中输入时调用onChange处理程序来实现这一点。

所以通常情况下,当有输入更改时,onChange处理程序将使用 "合成事件" 作为参数调用。

onChange = (e) => setInput(e.target.value)

TimePicker 和 onChange 处理程序

但是,在 MUI 的 TimePicker 组件的情况下,无论何时调用 onChange 处理程序,提供给处理程序的参数都不是 "合成事件",而是组件的数据值。

Object { "$L": "en", "$u": undefined, "$d": Date Tue Jun 20 2023 10:10:00 GMT+0530 (India Standard Time), "$x": {}, "$y": 2023, "$M": 5, "$D": 20, "$W": 2, "$H": 0, "$m": 10,  }

如您所见,没有 event.target.value,值只是 event

因此,当 Formik 尝试访问 event.target.value 时,它无法成功。因此,该值不会反映在组件中。

解决方案

为了解决这个问题,您需要创建自己的自定义 onChange 事件处理程序。您可以通过使用 Formik 中提供的 setFieldValue 来实现这一点。

这将自动为您设置 mondayFrom 字段的值。

<TimePicker
  {...field}
  ampm={false}
  format="HH:mm"
  onChange={(e) => form.setFieldValue(field.name, e)}
  slotProps={{
    textField: {
      label: "Monday From",
      size: "small",
      fullWidth: true,
    },
  }}
/>

上面的数据对象 e 还具有一个属性 $d,您可以使用它来获取字符串格式的日期时间值:

console.log(e["$d"])
// 日期 Tue Jun 20 2023 10:10:00 GMT+0530 (India Standard Time)

希望这可以帮助您!

英文:

Gist

The problem here is, that the component that you are using (TimePicker), behaves a bit differently than other components.

Formik and onChange handler

Formik, as you may know, makes it easier to develop forms in react. It does this, maintaing internal state of all input components, and by calling onChange handler whenever user enters input in the input component.

So normally, when there is a input change, onChange handles gets called with "synthetic event" as an argument.

onChange = (e) =&gt; setInput(e.target.value)

TimePicker and onChange handler

But, in the case of TimePicker component in MUI, whenever the onChange handler is called, arguments that is provided to the handler, is not "synthetic event", but the component's data value.

Object { &quot;$L&quot;: &quot;en&quot;, &quot;$u&quot;: undefined, &quot;$d&quot;: Date Tue Jun 20 2023 10:10:00 GMT+0530 (India Standard Time), &quot;$x&quot;: {}, &quot;$y&quot;: 2023, &quot;$M&quot;: 5, &quot;$D&quot;: 20, &quot;$W&quot;: 2, &quot;$H&quot;: 0, &quot;$m&quot;: 10, … }

As you can see, there is no event.target.value, the value is just event.

So, when Formik tries to access event.target.value, it is not able to. And therefore, the value is not reflected in the component.

The Solution

In order to circumvent this problem, you need to create your own custom onChange event handler. And you can do this by using, setFieldValue which is present in Formik.

And this will essentially set the mondayFrom field value automatically for you.

       &lt;TimePicker
{...field}
ampm={false}
format=&quot;HH:mm&quot;
onChange={(e) =&gt; form.setFieldValue(field.name, e)}
slotProps={{
textField: {
label: &quot;Monday From&quot;,
size: &quot;small&quot;,
fullWidth: true,
},
}}
/&gt;

The data object e above, also has a property "$d" using which you could get the date time value in string format:

   console.log(e[&quot;$d&quot;])
// Date Tue Jun 20 2023 10:10:00 GMT+0530 (India Standard Time)

Hope this helps!

huangapple
  • 本文由 发表于 2023年6月13日 13:36:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76461941.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定