dante
dante

Reputation: 1111

how to build custom onSubmit function with formik and typescript, hooks

I'm building form onSubmit functions with useCallback hooks which will be used in formik

my component using formik might be looks like this,

  import { useContactForm } from './useContactForm'
  //some functional component
  const customSubmit = .... /some submit function 
  const { initialValues, handleSubmit } = useContactForm(customSubmit); 
  const formik = useFormik({
    initialValues,
    onSubmit: handleSubmit //something like this
  });

  return(
    <form onSubmit ={formik.handleSubmit}>
      <input
         id="email"
         name="email"
         type="email"
         onChange={formik.handleChange}
         value={formik.values.email}
      />
      <input 
         id="password"
         name="password"
         type="password"
         onChange={formik.handleChange}
         value={formik.values.password}
      />
      <button type="submit">Submit</button>
    </form>
  ) 

and my useContactForm.ts looks like this. // useContactForm.ts

import { useCallback } from 'react';

interface IContactFormFields {
  email: string,
  password: string
}
type ISubmitFormType = (value: IContactFormFields, e?: React.FormEvent<HTMLFormElement>) => Promise<void>;

const useContactForm = (submitForm: ISubmitFormType) => {
  const handleSubmit = useCallback(
    ( formFields : IContactFormFields ) => {
      return submitForm(formFields).then(() => {
        console.log('form submitted');
      })
    },[]);

  const initialValues: IContactFormFields = {
    email: "",
    password: "",
  };
  return {
    handleSubmit,
    initialValues,
  }
}

export default useContactForm;

my problem useContactForm should get custom submit function name submitForm as a parameter.

then, how my ISubmitFormType should looks like?

Upvotes: 3

Views: 7173

Answers (3)

yaputra jordi
yaputra jordi

Reputation: 523

I might be too late for this but I found that your question interesting and I tried to work around it.

Here are my solutions:

  1. Firstly, since you won't be able to get the FormEvent anyway, I replaced it with more useful feature by formik to your useContactForm hook:
// use-contact-form.ts

import { FormikConfig, FormikHelpers } from "formik";
import { useCallback } from "react";

export interface IContactFormFields {
  email: string;
  password: string;
}

export type ISubmitFormType = FormikConfig<IContactFormFields>["onSubmit"];

const useContactForm = (submitForm: ISubmitFormType) => {
  const handleSubmit: ISubmitFormType = useCallback(
    async (
      formFields: IContactFormFields,
      formikBag: FormikHelpers<IContactFormFields>
    ) => {
      const result = await submitForm(formFields, formikBag);
      console.log("form submitted");
      return result;
    },
    []
  );

  const initialValues: IContactFormFields = {
    email: "",
    password: "",
  };

  return {
    handleSubmit,
    initialValues,
  };
};

Notice the ISubmitFormType type. We only need to use what was provided by formik themself.

  1. After that you can define your custom submit function where you also can access the formikHelper api like usual.
// custom-submit-fn.ts

import { ISubmitFormType } from "./use-contact-form";

const customSubmitFn: ISubmitFormType = async (values, formikHelpers) => {
  // do something
};

export default customSubmitFn;
  1. Finally, you can stitch them together on your component
// contact-form.tsx

import { useFormik } from "formik";
import { useContactForm } from "./use-contact-form";
import { customSubmitFn } from "./custom-submit-fn";

export default function FunctionalContactForm() {
  const { initialValues, handleSubmit } = useContactForm(customSubmitFn);
  const formik = useFormik({
    initialValues,
    onSubmit: handleSubmit, //something like this
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <input
        id="email"
        name="email"
        type="email"
        onChange={formik.handleChange}
        value={formik.values.email}
      />
      <input
        id="password"
        name="password"
        type="password"
        onChange={formik.handleChange}
        value={formik.values.password}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

Upvotes: 0

C-Note187
C-Note187

Reputation: 644

My 'custom onSubmit' just needed additional data passed to it. There's an answer on Formik's github that worked for me. So if anyone is having trouble passing custom data through the Formik onSubmit or handleSubmit, check this out: https://github.com/jaredpalmer/formik/issues/1900#issuecomment-645034575

Upvotes: 0

jmunsch
jmunsch

Reputation: 24089

How to figure out what the type should be in this case.

  • what is the variable ( function, int, string, null, number, etc )
  • if it's a function, what arguments go in, and what is returned, and how is the return used.

From your example, how submitForm is used:

submitForm(formFields).then(() => {
        console.log('form submitted');
      })

Is it a function?: yes

  • type so far: () => unknown

What goes in: formFields

  • type so far: (formFields) => unknown

What is returned: A Promise

  • type so far: (formFields) => Promise<unknown>

What we have so far:

type ISubmitFormType = (formFields: unknown) => Promise<unknown>

(submitForm: ISubmitFormType) => {...}

Upvotes: 1

Related Questions