在 Formik Form 上更新 initialValues props不会更新输入值

IT技术 javascript reactjs formik
2021-05-07 17:39:28

我使用带有前向引用的 formik 形式

表单.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,当我选择第二个选项卡时,我想value用 Formik 表单更新输入值(最初来自 的商店状态),但更新initialValues特定于该组件的状态作为initialValuesprops传递Formik组件。

TabsForm.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;

单击第二个选项卡时;

  • initialValues状态TabsForms.js更新,以便value.input= 30000;
  • initialValues在这两个支柱Form.jsFormikWithRef.js也反映value.input=3000
  • 但是,输入不更新,使用useField钩从forimkMoneyBox.js组件中,field对象不具有value30000,而不是它的任何字段值是以前,这是为什么?

我创建了一个CodeSandbox来查看所有使用的组件,并创建了控制台日志来查看 Formik 确实收到了更新的值,但似乎没有应用它。

我已经坚持了几天,似乎无法找到解决方案,任何帮助将不胜感激。

3个回答

如果您希望输入的值在更改时更改initialValues,则需要Formik将 propenableReinitialize作为传递给组件true

因此,您需要在代码中更改的是TabsForm.js传递给Form组件的 propenableReinitialize

<Form
  enableReinitialize
  initialValues={initialValues}
  onSubmit={onFormSubmit}
  formRef={formRef}
>
  <FieldWrapper>
    <MoneyBox name="input" currencySymbol={"£"} />
  </FieldWrapper>
</Form>

在你Form.js传递给Formik组件的props中

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

我不太确定您的业务逻辑应该如何工作,但这里有一个包含上述更改工作示例

(解决方案代码沙盒)

它被称为initialValues,那么为什么您希望它在您更改它时更新表单值呢?(但是,您可以使用enableReinitializeprop来要求它这样做,正如@Vencovsky 在另一个答案中提到的那样。)

要将所需的值(value.inputeasy-peasy商店中)绑定到 formik 输入,您可以使用:

const [field, meta, helpers] = useField(props);
useEffect(() => {
  helpers.setValue(value.input)
}, [value])

每次valuein store 更改时,它都会更新 formik 输入字段的值

并且要更改 store 中状态的值,您可以使用设置选项卡的方式。(使用easy-peasy商店。)

在 CodeSandbox 上运行

在第 49 行Tabs.js,它会在单击选项卡时更新值。

在第 19 行Input.js,它将输入值绑定到您的商店状态。

enableReinitialize={true} props会为你做的伎俩