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)