在 Formik Form 上更新 initialValues 道具不会更新输入值
Updating initialValues prop on Formik Form does not update input value
我像这样使用带有前向引用的 formik 表单
Form.js
import React from "react";
import FormikWithRef from "./FormikWithRef";
const Form = ({
formRef,
children,
initialValues,
validationSchema,
onSubmit
}) => {
return (
<FormikWithRef
validateOnChange={true}
validateOnBlur={true}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
ref={formRef}
>
{(props) => <form onSubmit={props.handleSubmit}>{children}</form>}
</FormikWithRef>
);
};
export default Form;
FormikWithRef.js
import React, { forwardRef, useImperativeHandle } from "react";
import { Formik } from "formik";
function FormikWithRef(props, ref) {
let _formikProps = {};
useImperativeHandle(ref, () => _formikProps);
return (
<Formik {...props}>
{(formikProps) => {
_formikProps = formikProps;
if (typeof props.children === "function") {
return props.children(formikProps);
}
return props.children;
}}
</Formik>
);
}
export default forwardRef(FormikWithRef);
我有一些选项卡,更新 easy-peasy
存储状态 type
,当我 select 第二个选项卡时,我想更新输入值(最初来自value
) 的存储状态与 Formik 形式,但更新特定于该组件的状态 initialValues
,该组件作为 initialValues
道具传递给 Formik
组件。
制表符Form.js
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import { useStoreState } from "easy-peasy";
import Form from "./Form";
import MoneyBox from "./MoneyBox";
const Container = styled.div`
width: 100%;
background-color: #dfdfdf;
`;
const FieldWrapper = styled.div`
padding: 20px 12px;
`;
const TabsForm = () => {
const [initialValues, setInitialValues] = useState();
const type = useStoreState((state) => state.type);
const value = useStoreState((state) => state.value);
const formRef = useRef(null);
const onFormSubmit = async (values) => {
console.log({ values });
};
useEffect(() => {
if (value && type) {
let filterVal = { ...value };
/* here is where I update the input value to be 3000,
the initial values get updated and in the `Form.js` file,
the console log from here also reflects this update,
however, the input field does not update? */
if (type === "Two") filterVal.input = 30000;
setInitialValues(filterVal);
}
}, [value, type]);
useEffect(() => {
// check initialValues has updated
console.log({ initialValues });
}, [initialValues]);
return (
<Container>
{initialValues && type ? (
<Form
initialValues={initialValues}
onSubmit={onFormSubmit}
formRef={formRef}
>
<FieldWrapper>
<MoneyBox name="input" currencySymbol={"£"} />
</FieldWrapper>
</Form>
) : null}
</Container>
);
};
export default TabsForm;
点击第二个标签时;
TabsForms.js
中的 initialValues
状态更新,因此 value.input
= 30000
;
-
Form.js
和 FormikWithRef.js
中的 initialValues
属性也反映了 value.input
= 3000
- 但是,输入没有更新,在
MoneyBox.js
组件中使用来自 forimk
的 useField
钩子,field
对象没有 value
的 30000
,而不是以前的字段值,这是为什么?
我创建了一个 CodeSandbox 来查看所有使用的组件,并创建了控制台日志以查看 Formik 确实收到了更新的值,但似乎没有应用它。
我已经坚持了几天,似乎无法找到解决方案,任何帮助将不胜感激。
如果您希望在更改 initialValues
时更改输入的值,则需要将属性 enableReinitialize
作为 true
传递给 Formik
组件。
所以,您需要在代码中更改的是 TabsForm.js
将道具 enableReinitialize
传递给您的 Form
组件
<Form
enableReinitialize
initialValues={initialValues}
onSubmit={onFormSubmit}
formRef={formRef}
>
<FieldWrapper>
<MoneyBox name="input" currencySymbol={"£"} />
</FieldWrapper>
</Form>
然后在您的 Form.js
中将该道具传递给 Formik
组件
const Form = ({
formRef,
children,
initialValues,
validationSchema,
onSubmit,
enableReinitialize
}) => {
return (
<FormikWithRef
enableReinitialize={enableReinitialize}
validateOnChange={true}
validateOnBlur={true}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
ref={formRef}
>
{(props) => <form onSubmit={props.handleSubmit}>{children}</form>}
</FormikWithRef>
);
};
我不太确定您的业务逻辑应该如何工作,但这里是 working example 进行了上述更改。
它叫做 initialValues
,那么为什么您希望它在您更改它时更新表单值呢? (但是您可以使用 enableReinitialize
道具要求它这样做,正如@Vencovsky 在另一个答案中提到的那样。)
要将您想要的值(easy-peasy
商店中的 value.input
)绑定到 formik 输入,您可以使用:
const [field, meta, helpers] = useField(props);
useEffect(() => {
helpers.setValue(value.input)
}, [value])
每次 value
存储更改时,它都会更新 formik 输入字段的值。
并且要更改存储中状态的值,您可以使用设置选项卡的方式。 (使用 easy-peasy
商店。)
在 Tabs.js
的第 49 行,它会在单击选项卡时更新值。
在 Input.js
的第 19 行,它将输入值绑定到您的存储状态。
enableReinitialize={true} 属性将为您解决问题
我像这样使用带有前向引用的 formik 表单
Form.js
import React from "react";
import FormikWithRef from "./FormikWithRef";
const Form = ({
formRef,
children,
initialValues,
validationSchema,
onSubmit
}) => {
return (
<FormikWithRef
validateOnChange={true}
validateOnBlur={true}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
ref={formRef}
>
{(props) => <form onSubmit={props.handleSubmit}>{children}</form>}
</FormikWithRef>
);
};
export default Form;
FormikWithRef.js
import React, { forwardRef, useImperativeHandle } from "react";
import { Formik } from "formik";
function FormikWithRef(props, ref) {
let _formikProps = {};
useImperativeHandle(ref, () => _formikProps);
return (
<Formik {...props}>
{(formikProps) => {
_formikProps = formikProps;
if (typeof props.children === "function") {
return props.children(formikProps);
}
return props.children;
}}
</Formik>
);
}
export default forwardRef(FormikWithRef);
我有一些选项卡,更新 easy-peasy
存储状态 type
,当我 select 第二个选项卡时,我想更新输入值(最初来自value
) 的存储状态与 Formik 形式,但更新特定于该组件的状态 initialValues
,该组件作为 initialValues
道具传递给 Formik
组件。
制表符Form.js
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import { useStoreState } from "easy-peasy";
import Form from "./Form";
import MoneyBox from "./MoneyBox";
const Container = styled.div`
width: 100%;
background-color: #dfdfdf;
`;
const FieldWrapper = styled.div`
padding: 20px 12px;
`;
const TabsForm = () => {
const [initialValues, setInitialValues] = useState();
const type = useStoreState((state) => state.type);
const value = useStoreState((state) => state.value);
const formRef = useRef(null);
const onFormSubmit = async (values) => {
console.log({ values });
};
useEffect(() => {
if (value && type) {
let filterVal = { ...value };
/* here is where I update the input value to be 3000,
the initial values get updated and in the `Form.js` file,
the console log from here also reflects this update,
however, the input field does not update? */
if (type === "Two") filterVal.input = 30000;
setInitialValues(filterVal);
}
}, [value, type]);
useEffect(() => {
// check initialValues has updated
console.log({ initialValues });
}, [initialValues]);
return (
<Container>
{initialValues && type ? (
<Form
initialValues={initialValues}
onSubmit={onFormSubmit}
formRef={formRef}
>
<FieldWrapper>
<MoneyBox name="input" currencySymbol={"£"} />
</FieldWrapper>
</Form>
) : null}
</Container>
);
};
export default TabsForm;
点击第二个标签时;
TabsForms.js
中的initialValues
状态更新,因此value.input
=30000
;-
Form.js
和FormikWithRef.js
中的initialValues
属性也反映了value.input
=3000
- 但是,输入没有更新,在
MoneyBox.js
组件中使用来自forimk
的useField
钩子,field
对象没有value
的30000
,而不是以前的字段值,这是为什么?
我创建了一个 CodeSandbox 来查看所有使用的组件,并创建了控制台日志以查看 Formik 确实收到了更新的值,但似乎没有应用它。
我已经坚持了几天,似乎无法找到解决方案,任何帮助将不胜感激。
如果您希望在更改 initialValues
时更改输入的值,则需要将属性 enableReinitialize
作为 true
传递给 Formik
组件。
所以,您需要在代码中更改的是 TabsForm.js
将道具 enableReinitialize
Form
组件
<Form
enableReinitialize
initialValues={initialValues}
onSubmit={onFormSubmit}
formRef={formRef}
>
<FieldWrapper>
<MoneyBox name="input" currencySymbol={"£"} />
</FieldWrapper>
</Form>
然后在您的 Form.js
中将该道具传递给 Formik
组件
const Form = ({
formRef,
children,
initialValues,
validationSchema,
onSubmit,
enableReinitialize
}) => {
return (
<FormikWithRef
enableReinitialize={enableReinitialize}
validateOnChange={true}
validateOnBlur={true}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
ref={formRef}
>
{(props) => <form onSubmit={props.handleSubmit}>{children}</form>}
</FormikWithRef>
);
};
我不太确定您的业务逻辑应该如何工作,但这里是 working example 进行了上述更改。
它叫做 initialValues
,那么为什么您希望它在您更改它时更新表单值呢? (但是您可以使用 enableReinitialize
道具要求它这样做,正如@Vencovsky 在另一个答案中提到的那样。)
要将您想要的值(easy-peasy
商店中的 value.input
)绑定到 formik 输入,您可以使用:
const [field, meta, helpers] = useField(props);
useEffect(() => {
helpers.setValue(value.input)
}, [value])
每次 value
存储更改时,它都会更新 formik 输入字段的值。
并且要更改存储中状态的值,您可以使用设置选项卡的方式。 (使用 easy-peasy
商店。)
在 Tabs.js
的第 49 行,它会在单击选项卡时更新值。
在 Input.js
的第 19 行,它将输入值绑定到您的存储状态。
enableReinitialize={true} 属性将为您解决问题