【问题标题】:Updating initialValues prop on Formik Form does not update input value更新 Formik Form 上的 initialValues 道具不会更新输入值
【发布时间】:2021-11-08 03:20:02
【问题描述】:

我使用带有前向引用的 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,当我选择第二个选项卡时,我想用一个更新输入值(最初来自 value 的存储状态) Formik 表单,但更新特定于该组件的状态 initialValues,该组件作为 initialValues 属性传递给 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;

点击第二个标签时;

  • TabsForms.js 中的initialValues 状态更新,因此value.input = 30000;
  • Form.jsFormikWithRef.js 中的 initialValues 属性也反映了 value.input = 3000
  • 但是,输入不会更新,使用MoneyBox.js 组件中forimkuseField 挂钩,field 对象没有value30000,而是任何字段以前的值,为什么会这样?

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

我在这个问题上困扰了几天,似乎找不到解决方案,任何帮助将不胜感激。

【问题讨论】:

    标签: javascript reactjs formik


    【解决方案1】:

    enableReinitialize={true} 道具将为您解决问题

    【讨论】:

    • 请花时间提供高质量的答案。你能解释一下它为什么起作用并添加一个小例子吗?请看How to Answer?
    【解决方案2】:

    (Solution CodeSandbox)

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

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

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

    每当 value in store 发生变化时,它都会更新 formik 输入字段的值。

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

    Run It On CodeSandbox

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

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

    【讨论】:

      【解决方案3】:

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

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

      <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,上面做了一些更改。

      【讨论】:

      • 谢谢。不知道道具存在!
      猜你喜欢
      • 1970-01-01
      • 2016-12-17
      • 1970-01-01
      • 2013-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-09
      相关资源
      最近更新 更多