Using setErrors for with Formik DOM, useFormikContext
Tags: react, formik, javascript, tutorial
Published: 2021-10-27 18:22:20

TL;DR Hi! everyone in this article I would like to share you about using of **setErrors** within the Formik DOM, this is for everyone who struggling 😫😫 of setting an error messages from the backend request.

In this scenario, I used **useField** for separating of Fields from Form

Follow this proceedures step by step 😊

**1.)** First of all, make sure you have installed the following dependencies.

    Formik
    npm install Formik --save

    Yup
    npm install Formik --save

**2.)** Second, Create a component for custom formik as HOC

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/idp5bb1v3zfs9azlw6vo.png)

**3.)** Third, follow this code:

**3.1.)** Import the following dependencies:

```
import { useEffect, Fragment } from "react";
import { useFormikContext } from "formik";
import { Formik } from "formik";
```
Since we are using Formik DOM, so we are able to use **useFormikContext**. Because, its easy to read and effective separation of code

**3.2.)** Using a Component for setErrors of Formik library

This component is responsible for receiving a prop of error messages (**setErrors**) and setting an errors from our backend request that we want to show on our form or within the fields.

I used **useEffect** as watcher of **setErrors** prop for every time the errors from backend request has changes.

I used **useFormikContext** to have access in **setErrors** from the Formik Provider as Formik component.

```
const FormikWithSetErrors = ({ children, setErrors })  => {

    const { setErrors:setBackendErrors } = useFormikContext();

    useEffect(()=>{
        if(setErrors) setBackendErrors(setErrors);
    },[setErrors]);

    return <Fragment>{children}</Fragment>;
}
```
**3.3.)** Get values from Formik provider

I wrapped the Formik component while our **FormikWithSetErrors** is our child component. To access the formik provider's value.

```
const FormikForm = ({ children, setErrors, ...otherProps }) => {
    return (
        <Formik {...otherProps}>
            <FormikWithSetErrors setErrors={setErrors}>
                {children}
            </FormikWithSetErrors>
        </Formik> 
    );
}
```

**Formik/index**
```
import { useEffect, Fragment } from "react";
import { useFormikContext } from "formik";
import { Formik } from "formik";

const FormikWithSetErrors = ({ children, setErrors })  => {

    const { setErrors:setBackendErrors } = useFormikContext();

    useEffect(()=>{
        if(setErrors) setBackendErrors(setErrors);
    },[setErrors]);

    return <Fragment>{children}</Fragment>;
}

const FormikForm = ({ children, setErrors, ...otherProps }) => {
    return (
        <Formik {...otherProps}>
            <FormikWithSetErrors setErrors={setErrors}>
                {children}
            </FormikWithSetErrors>
        </Formik> 
    );
}

export default FormikForm;

```
For UI 

I used Material-UI for faster demonstration and easy frontend development

I made at least two component for sample form fields that we will use to demonstrate the Formik.

      ./components
       ../Button/index.js
       ../TextField/index.js

 
Here's the snippet code of two components:


**Button/index.js**
```
import { useFormikContext } from "formik";
import { Button } from "@material-ui/core";

const FormButton = ({ children, otherProps }) => {
  const { submitForm } = useFormikContext();

  const handleSubmit = () => {
    // this will trigger the <Formik> prodiver
    submitForm();
  };

  const configFormButton = {
    ...otherProps,
    variant: "contained",
    color: "primary",
    fullWidth: true,
    onClick: handleSubmit
  };

  return <Button {...configFormButton}>{children}</Button>;
};

export default FormButton;
```


**TextField/index.js**
```
import { TextField } from "@material-ui/core";
import { useField } from "formik";

const FormTextField = ({ name, ...otherProps }) => {
  const [field, meta] = useField(name);

  const configFormTextField = {
    ...field,
    ...otherProps,
    variant: "outlined",
    fullWidth: true,
    size: "small"
  };

  if (meta && meta.error) {
    configFormTextField.error = true;
    configFormTextField.helperText = meta.error;
  }

  return <TextField {...configFormTextField} />;
};

export default FormTextField;
```

I created a validation schema for client validation use. Using a library **Yup**

      ./components
         ../validationSchema.js


**validationSchema.js**
```
import * as Yup from "yup";

const ValidationSchema = Yup.object().shape({
  firstName: Yup.string().required("First Name is required")
});

export default ValidationSchema;
```

I created a fakeBackend hook request using **setTimeout**, just to simulate the producing of error response message.

      ./components
         ../fakeBackend.js


**fakeBackend.js**
```
import { useState } from "react";

const useFakeBackend = () => {
  const [errors, setErrors] = useState({});

  // simulating a backend request
  const setRequest = () => {
    setTimeout(() => {
      setErrors((errors) => ({
        firstName: "Please enter a valid First Name "
      }));
    }, 2000);
  };

  return { errors, setRequest };
};

export default useFakeBackend;
```

Finally!!!! Now were almost there!! 😊😊😊

This is the final setup of our created components for simulation

**App.js**
```
import { Grid } from "@material-ui/core";
import Formik from "./components/Formik/index";
import Button from "./components/Button/index";
import TextField from "./components/TextField/index";
import ValidationSchema from "./components/validationSchema";
import useFakeBackend from "./components/fakeBackend";

export default function App() {
  const { errors, setRequest } = useFakeBackend();

  return (
    <Formik
      initialValues={{ firstName: "" }}
      validationSchema={ValidationSchema}
      enableReinitialize={true}
      setErrors={errors}
      onSubmit={() => {
        alert("backend requesting...");
        setRequest();
      }}
    >
      <Grid container spacing={2}>
        <Grid item xs={12}>
          <label>First Name</label>
        </Grid>
        <Grid item xs={12}>
          <TextField name="firstName" />
        </Grid>
        <Grid item xs={12}>
          <Button>Submit</Button>
        </Grid>
      </Grid>
    </Formik>
  );
}

```

Now, our UI form is now done!!!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dpoqfmuj86pz6h0ifr9.png)

You can fork the whole sample project here:
https://codesandbox.io/s/formik-context-jsoe0?file=/src/App.js


That's all thank you guys!!! 😊😊😊