I am using useFormik
hook to use Formik with my forms. In the configuration I have set validate
, onSubmit
and initialValues
keys. I want to sanitize my inputs like trimming and escaping. For email I also want to use normalizeEmail
from validator.js
. I am not able to find where to put the sanitization code - do I put it in the formik config or in validate function. I realize that I can use setFieldValue
from formik, but I don't want to change the formik.handleChange
functionality as it handles the form states and don't want to screw that up.
Here is the code:
import { useEffect, useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
import { NavLink as RouterLink, useHistory, useLocation } from "react-router-dom";
import Helmet from "react-helmet";
import {
Button,
LinearProgress,
Typography,
Paper,
Grid,
Box,
TextField
} from "@material-ui/core";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { useFormik } from "formik";
import { useSnackbar } from "notistack";
import CenterLayout from "../CenterLayout";
import { logInUser } from "../../features/user/userSlice";
import { useTheme } from "@material-ui/core/styles";
import { useTranslation } from "react-i18next";
import isEmail from 'validator/es/lib/isEmail';
const Login = () => {
const { isLoadingLogin, errorLoginCode } = useSelector((state) => state.user);
const prevIsLoadingLoginRef = useRef();
const dispatch = useDispatch();
const history = useHistory();
const location = useLocation();
const theme = useTheme();
const isXS = useMediaQuery(theme.breakpoints.down("xs"));
const { enqueueSnackbar } = useSnackbar();
const { t } = useTranslation();
const formik = useFormik({
initialValues: {
email: "",
password: "",
},
onSubmit: (values) => {
dispatch(logInUser(values));
},
validate: (values) => {
const errors = {};
if (!values.email) {
errors.email = t('form.required');
} else if (
!isEmail(values.email)
) {
errors.email = t('loginPage.invalidEmail');
}
if (!values.password) {
errors.password = t('form.required');
}
return errors;
},
});
useEffect(() => {
if (prevIsLoadingLoginRef.current && !isLoadingLogin) {
if (errorLoginCode.length === 0) {
formik.resetForm();
enqueueSnackbar(t("loginPage.loginSuccess"), {
variant: "success",
});
const { from } = location.state || { from: { pathname: "/dashboard" } };
history.replace(from);
} else {
enqueueSnackbar(
`${t("loginPage.loginFailed")}: ${t("api." + errorLoginCode)}`,
{ variant: "error" }
);
}
}
prevIsLoadingLoginRef.current = isLoadingLogin;
}, [
isLoadingLogin,
errorLoginCode,
history,
location,
formik,
enqueueSnackbar,
t,
]);
console.log("dbg1", formik);
return (
<CenterLayout>
<Helmet title="Circuittutor - Login" />
<Grid item xs={12} sm={8} md={4}>
<Paper elevation={isXS ? 0 : 1}>
<Box p={2}>
<Typography
variant="h6"
align="center"
color="secondary"
gutterBottom
>
{t("loginPage.form")}
</Typography>
<form onSubmit={formik.handleSubmit}>
<TextField
name="email"
type="email"
label={t("loginPage.email")}
fullWidth
style={{ marginBottom: theme.spacing(2) }}
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={
formik.touched.email &&
Boolean(formik.errors.email)
}
helperText={
formik.touched.email && formik.errors.email
}
/>
<TextField
name="password"
type="password"
label={t("loginPage.password")}
fullWidth
style={{ marginBottom: theme.spacing(2) }}
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={
formik.touched.password &&
Boolean(formik.errors.password)
}
helperText={
formik.touched.password && formik.errors.password
}
/>
{isLoadingLogin && (
<LinearProgress style={{ marginBottom: theme.spacing(2) }} />
)}
<Button
variant="contained"
color="secondary"
disabled={isLoadingLogin}
type="submit"
fullWidth={isXS}
>
{t("form.submit")}
</Button>
</form>
<Button
exact
variant="text"
disableElevation
color="primary"
component={RouterLink}
to="/forgotPassword"
style={{ marginTop: theme.spacing(2), padding: 0 }}
>
{t('loginPage.forgotPasswordBtn')}
</Button>
</Box>
</Paper>
</Grid>
</CenterLayout>
);
};
export default Login;
All you need to do is to intercept onChange event on you input field, do your sanitization logic and then call the setFieldValue
helper with new computed value. You don't need to worry about anythin related to Formik internals - it's official way to provide custom input handlers