Формик улов-22 - PullRequest
       15

Формик улов-22

0 голосов
/ 02 августа 2020

Я новичок в React, и при использовании Formik я столкнулся с ловушкой 22, из-за которой у меня, кажется, есть психический блок. Если я использую withFormik (), то мой компонент не может использовать хуки в своем обработчике отправки.

import React, { useEffect } from "react";
import { Form, Field, withFormik } from "formik";
import { useDatabase, useAlerts } from "./Hooks";

const MyForm = props => {
  const { resetForm, dirty, isSubmitting, setSubmitting } = props;
  const { loadData, saveData } = useDatabase();
  const { success } = useAlerts();
  const reset = data => resetForm({ values: data });

  useEffect(() => {
    loadData().then(data => reset(data));
  }, []);

  // Problem: How can I execute this on submit?
  const handleSubmit = async values => {
    await saveData(values);
    reset(values);
    success("Values saved");
    setSubmitting(false);
  };

  return (
    <Form>
      <h1>Catch 22</h1>
      <Field
        name="firstName"
        placeholder="First name"
        readOnly={isSubmitting}
      />
      <Field name="lastName" placeholder="Last name" readOnly={isSubmitting} />
      <input disabled={!dirty} type="submit" />
      <input type="reset" />
    </Form>
  );
};

export default withFormik({
  mapPropsToValues: () => ({
    firstName: "",
    lastName: ""
  }),
  enableReinitialize: true,
  handleSubmit: () => {
    // Has no access to saveData() and success() hook methods
  }
})(MyForm);

https://codesandbox.io/s/sleepy-blackburn-q1mt4?file= / src / MyForm. js

В качестве альтернативы, если я не использую withFormik, я не могу сбросить форму, когда мои данные загружены, потому что у меня нет ссылки на resetForm.

import React, { useEffect } from "react";
import { Form, Field, Formik } from "formik";
import { useDatabase, useAlerts } from "./Hooks";

const MyForm = props => {
  const { loadData, saveData } = useDatabase();
  const { success } = useAlerts();

  // Problem: how can I reset the form on data load?
  useEffect(() => {
    loadData().then(data => resetForm({ values: data }));
  }, []);

  const initialValues = {
    firstName: "",
    lastName: ""
  };

  const handleSubmit = async (values, { setSubmitting, resetForm }) => {
    await saveData(values);
    resetForm({ values });
    success("Values saved");
    setSubmitting(false);
  };

  return (
    <Formik
      initialValues={initialValues}
      onSubmit={handleSubmit}
      enableReinitialize={true}
    >
      {({ isSubmitting, dirty }) => (
        <Form>
          <h1>Catch 22</h1>
          <Field
            name="firstName"
            placeholder="First name"
            readOnly={isSubmitting}
          />
          <Field
            name="lastName"
            placeholder="Last name"
            readOnly={isSubmitting}
          />
          <input disabled={!dirty} type="submit" />
          <input type="reset" />
        </Form>
      )}
    </Formik>
  );
};

export default MyForm;

https://codesandbox.io/s/hardcore-sound-048wf?file= / src /MyForm.js

Как лучше всего это сделать?

1 Ответ

0 голосов
/ 02 августа 2020

Кажется, что написание проблемы заставило некоторых мозгов начать вращаться, и я придумал возможное решение.

Я ввел такой контекст ...

import React, { useState, useContext } from "react";
import { useDatabase } from "./Hooks";

export const DataContext = React.createContext(null);
export const DataContextConsumer = DataContext.Consumer;
export const useDataContext = () => useContext(DataContext);

export const DataContextProvider = props => {
  const [data, setData] = useState({
    firstName: "",
    lastName: ""
  });
  const { loadData, saveData } = useDatabase();
  const load = async () => setData(await loadData());
  const save = async newData => await saveData(newData);
  const contextValues = { load, save, data };
  return (
    <DataContext.Provider value={contextValues}>
      {props.children}
    </DataContext.Provider>
  );
};

export const withDataContext = () => WrappedComponent => props => (
  <DataContextProvider>
    <WrappedComponent {...props} />
  </DataContextProvider>
);

export default {
  DataContext,
  DataContextConsumer,
  DataContextProvider,
  useDataContext,
  withDataContext
};

А затем передал свои данные в InitialValues ​​Formik. Теперь Formik получает новые значения при загрузке, и я могу вызывать хуки сохранения в обработчике отправки.

import React, { useEffect } from "react";
import { Form, Field, Formik } from "formik";
import { withDataContext, useDataContext } from "./DataContext";
import { useAlerts } from "./Hooks";

const MyForm = () => {
  const { load, save, data } = useDataContext();
  const { success } = useAlerts();

  useEffect(() => {
    load();
  }, []);

  const handleSubmit = async (values, { setSubmitting, resetForm }) => {
    await save(values);
    resetForm({ values });
    success("Values saved " + JSON.stringify(values));
    setSubmitting(false);
  };

  return (
    <Formik
      initialValues={data}
      onSubmit={handleSubmit}
      enableReinitialize={true}
    >
      {({ isSubmitting, dirty }) => (
        <Form>
          <h1>Catch 22</h1>
          <Field
            name="firstName"
            placeholder="First name"
            readOnly={isSubmitting}
          />
          <Field
            name="lastName"
            placeholder="Last name"
            readOnly={isSubmitting}
          />
          <input disabled={!dirty} type="submit" />
          <input type="reset" />
        </Form>
      )}
    </Formik>
  );
};

export default withDataContext()(MyForm);

https://codesandbox.io/s/throbbing-cache-txnit?file= / src / MyForm. js

Возможно, это классический c случай решения проблемы React с помощью подъема состояния .

...