jeffedsell
jeffedsell

Reputation: 135

Formik object doesn't render

I created a custom input called <FormInput> and applied useField() and useFormikContext() to it:

const [field, meta] = useField(props);
const { setFieldValue } = useFormikContext();

<FormInput> is part of a library called UI. I'm importing the library and trying to create a very simple form to test, a single field, the only validation being that it's required:

import React, { useContext } from "react";
import { DataContext } from "../../context/DataContext";
import * as UI from "@tui/uilibrary";
import { composeThemeFromProps } from "@css-modules-theme/react";
import styles from "./EnrollStep5.module.scss";

import { Formik, Form } from "formik";
import * as Yup from "yup";

const EnrollStep5 = (props) => {
  const context = useContext(DataContext);
  const theme = composeThemeFromProps(styles, [context, props]);

  return (
    <Formik
      initialValues={{
        name: "",
      }}
      validationSchema={Yup.object().shape({
        name: Yup.string().required("Required"),
      })}
    >
      {(props) => {
        <Form className={theme.EnrollStep2}>
          <UI.FormInput type={"text"} name={"name"} label={"Name"} />
        </Form>;
      }}
    </Formik>
  );
};

export default EnrollStep5;

This comes up blank. The Formik object appears in the Component browser, but shows as if it has no children. I have the feeling this is just due to inexperience and that I'm close. What am I doing wrong?

Upvotes: 0

Views: 886

Answers (2)

Poll&#225;k Bence
Poll&#225;k Bence

Reputation: 59

You need to use <Field> component inside of <Form>...</Form> like this:

<Formik initialValues={{name: ""}}>
  <Form>
    <Field name="name" placeholder="Name:"></Field>
  </Form>
</Formik>

<Field> component will pass their value to formik and it can handle submit and etc.
You can create custom Field component:

<Formik initialValues={{ name: "" }}>
  <Form>
    <Field name="name" placeholder="Name:">
       {({ field }) => (
         <CustomInput {..field} />
       )}
    </Field>
  </Form>
</Formik>

<CustomInput> should include a html <input/> element or you can use flowbite, materialUI input components like this.

If you want to pass error or touched objects to custom components you should try this solution:

<Formik initialValues={{ name: "" }}>
    {({ values, errors, touched }) => (
      <Form>
        <Field name="name" placeholder="Name:">
          {({ field }) => (
            <CustomInput {...field} errors={errors} value={values}/>
          )}
        </Field>
      </Form>
    )}
</Formik>

Upvotes: 0

mirco
mirco

Reputation: 21

In short: Wrap the <Form>...</Form> in (parantheses) instead of {curly braces}.

Little more detailed:
So basically what is happening in your code with the curly braces is you are entering the callback function. So the <Form>...</Form> is just floating around somewhere in the function body. What you intend to do is to return it.
So you can either add a return statement (return <Form>...</Form>;) inside the curly braces or directly return the value without entering the function body. E.g. like (props) => <Form>...</Form> or (props) => (<Form>...</Form>), whichever you prefer.

Upvotes: 2

Related Questions