Обновление свойства initialValues ​​в Formik Form не обновляет входное значение - PullRequest
2 голосов
/ 06 августа 2020

Я использую форму 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 указывает c на тот компонент, который передается как initialValues prop компоненту 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.js и FormikWithRef.js также отразите, что value.input = 3000
  • Однако ввод не обновляется, используя ловушку useField из forimk в компоненте MoneyBox.js, объект field не имеет value из 30000, вместо этого это то же самое значение поля, которое было раньше, почему это?

Я создал CodeSandbox , чтобы увидеть все компоненты используется и журналы консоли, чтобы увидеть, что Formik действительно получает обновленное значение, но, похоже, не применяет его.

Я застрял на этом несколько дней и не могу найти Решение, любая помощь будет принята с благодарностью.

Ответы [ 2 ]

1 голос
/ 06 августа 2020

( Solution CodeSandbox )

Он называется initialValues, так почему вы ожидаете, что он обновит значения формы, когда вы его измените? (однако вы можете попросить его сделать это, используя enableReinitialize prop, как @Vencovsky упомянул в другом ответе.)

Для привязки желаемого значения (value.input в магазине easy-peasy) к входу formik , вы можете использовать:

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

, он будет обновлять значение поля ввода formik каждый раз, когда value в магазине изменяется.

и для изменения значения состояния в магазине , вы можете использовать его для настройки вкладок. (с использованием easy-peasy store.)

Run It On CodeSandbox

В строке 49 в Tabs.js значение обновляется при щелчке по вкладке.

В строке 19 в Input.js он связывает входное значение с состоянием вашего хранилища.

1 голос
/ 06 августа 2020

Если вы хотите, чтобы значение ввода изменялось при изменении initialValues, вам необходимо передать компоненту Formik опору enableReinitialize как true.

Итак, то, что вам нужно изменить в вашем коде, - это TabsForm.js передать компоненту Form опору 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>
  );
};

Я не совсем уверен, как ваша бизнес-логия c должна работать, но вот рабочий пример с изменениями выше.

...