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
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!!!
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!!! 😊😊😊
Top comments (0)