如何使用 Formik 进行输入清理?

How to use Input Sanitization with Formik?

我正在使用 useFormik 钩子将 Formik 用于我的表单。在配置中,我设置了 validateonSubmitinitialValues 键。我想清理我的输入,比如修剪和转义。对于电子邮件,我还想使用 validator.js 中的 normalizeEmail。我找不到放置清理代码的位置 - 我是将它放在 formik 配置中还是在验证函数中。我意识到我可以使用 formik 中的 setFieldValue,但我不想更改 formik.handleChange 功能,因为它处理表单状态并且不想搞砸它。

代码如下:

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;

您需要做的就是拦截输入字段上的 onChange 事件,执行清理逻辑,然后使用新的计算值调用 setFieldValue 帮助程序。您无需担心与 Formik 内部结构相关的任何事情 - 这是提供自定义输入处理程序的官方方式