简体   繁体   English

ReactJS 中的无效挂钩调用

[英]Invalid Hook Calls In Validation in ReactJS

I have a problem in implementing login validations in ReactJS.我在 ReactJS 中实现登录验证时遇到问题。 I'm using Material-UI and Formik and Yap.我正在使用 Material-UI 和 Formik 和 Yap。 I have implemented it but it has an error, it says invalid hook call.我已经实现了它,但它有一个错误,它说无效的钩子调用。 Hooks can only be called inside of the body of a function component.钩子只能在 function 组件的主体内部调用。

Pls check my code below:请在下面检查我的代码:

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/styles';
import { Card, CardHeader, CardContent, CardActions, Divider, Button, TextField } from '@material-ui/core';
import { useSelector, useDispatch } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { login } from '../../../actions';
import AccountCircle from '@material-ui/icons/AccountCircle';
import InputAdornment from '@material-ui/core/InputAdornment';
import LockIcon from '@material-ui/icons/Lock';
import { withFormik } from 'formik';

const useStyles = makeStyles((theme) => ({
  root: {},
  cardHeader: {
    backgroundColor: theme.palette.primary.main,
    color: 'white',
    display: 'flex',
    justifyContent: 'center',
    fontSize: '2rem',
    padding: '15px',
  },
  textFieldSection: {
    padding: '40px 40px 0 40px',
  },
  loginButtonSection: {
    padding: '18px 40px 40px 40px',
  },
  loginButton: {
    width: '100%',
    height: '50px',
    textTransform: 'none',
    fontSize: '18px',
  },
}));

const LoginForm = (props) => {
  const { className, ...rest } = props;

  const isLoggedIn = useSelector((state) => state.auth.isLoggedIn);
  const referer = props.referer;
  const dispatch = useDispatch();

  const signIn = () => {
    dispatch(login(values.username, values.password));
  };

  const { classes, values, touched, errors, isSubmitting, handleChange, handleBlur, handleSubmit } = props;

  if (isLoggedIn) {
    return <Redirect to={referer} />;
  }

  return (
    <Card {...rest} className={clsx(classes.root, className)}>
      <form onSubmit={handleSubmit}>
        <CardHeader
          title="LOGIN"
          classes={{
            title: classes.cardHeader,
          }}
          className={classes.cardHeader}
        />

        <CardContent className={classes.textFieldSection}>
          <TextField
            fullWidth
            label="Username"
            name="username"
            type="text"
            variant="outlined"
            value={values.username}
            onChange={handleChange}
            onBlur={handleBlur}
            helperText={touched.username ? errors.username : ''}
            error={touched.username && Boolean(errors.username)}
            InputProps={{
              endAdornment: (
                <InputAdornment>
                  <AccountCircle />
                </InputAdornment>
              ),
            }}
          />
          <TextField
            fullWidth
            label="Password"
            name="password"
            style={{ marginTop: '1rem' }}
            type="password"
            variant="outlined"
            value={values.password}
            onChange={handleChange}
            onBlur={handleBlur}
            helperText={touched.password ? errors.password : ''}
            error={touched.password && Boolean(errors.password)}
            InputProps={{
              endAdornment: (
                <InputAdornment>
                  <LockIcon />
                </InputAdornment>
              ),
            }}
          />
        </CardContent>

        <CardActions className={classes.loginButtonSection}>
          <Button
            color="primary"
            variant="contained"
            onClick={signIn}
            className={classes.loginButton}
            disabled={isSubmitting}
          >
            Log In
          </Button>
        </CardActions>
      </form>
    </Card>
  );
};

let yup = require('yup');

const Form = withFormik({
  mapPropsToValues: ({ username, password }) => {
    return {
      username: username || '',
      password: password || '',
    };
  },

  validationSchema: yup.object().shape({
    username: yup.string().required('Required'),
    password: yup.string().min(8, 'Password must contain at least 8 characters').required('Enter your password'),
  }),

  handleSubmit: (values, { setSubmitting }) => {
    setTimeout(() => {
      // submit to the server
      alert(JSON.stringify(values, null, 2));
      setSubmitting(false);
    }, 1000);
  },
})(LoginForm);

LoginForm.propTypes = {
  className: PropTypes.string,
};

export default LoginForm(useStyles)(Form);

withFormik与Formik

Create a higher-order React component class that passes props and form handlers (the "FormikBag") into your component derived from supplied options.创建一个高阶 React 组件 class ,它将道具和表单处理程序(“FormikBag”)传递到从提供的选项派生的组件中。

Just export the Form not LoginForm .只需导出Form而不是LoginForm Also to use classes do const classes = useStyles();还要使用classesconst classes = useStyles(); inside the component rather than passing it as props.在组件内部,而不是将其作为道具传递。

Working copy of your code is here 您的代码的工作副本在这里

Code Snippet代码片段

const useStyles = makeStyles(theme => ({
  root: {},
  cardHeader: {
    // backgroundColor: theme.palette.primary.main,
    backgroundColor: "blue",
    color: "white",
    display: "flex",
    justifyContent: "center",
    fontSize: "2rem",
    padding: "15px"
  },
  textFieldSection: {
    padding: "40px 40px 0 40px"
  },
  loginButtonSection: {
    padding: "18px 40px 40px 40px"
  },
  loginButton: {
    width: "100%",
    height: "50px",
    textTransform: "none",
    fontSize: "18px"
  }
}));

const LoginForm = props => {
  const { className, ...rest } = props;
  const classes = useStyles();

  const isLoggedIn = true;
  const referer = props.referer;

  const signIn = () => {
    console.log("signin");
  };

  const {
    // classes,
    values,
    touched,
    errors,
    isSubmitting,
    handleChange,
    handleBlur,
    handleSubmit
  } = props;

  if (isLoggedIn) {
    // return <Redirect to={referer} />;
    console.log("isLoggedIn", isLoggedIn);
  }

  return (
    <Card {...rest} className={clsx(classes.root, className)}>
      <form onSubmit={handleSubmit}>
        <CardHeader
          title="LOGIN"
          classes={{
            title: classes.cardHeader
          }}
          className={classes.cardHeader}
        />

        <CardContent className={classes.textFieldSection}>
          <TextField
            fullWidth
            label="Username"
            name="username"
            type="text"
            variant="outlined"
            value={values.username}
            onChange={handleChange}
            onBlur={handleBlur}
            helperText={touched.username ? errors.username : ""}
            error={touched.username && Boolean(errors.username)}
            InputProps={{
              endAdornment: (
                <InputAdornment>
                  <AccountCircle />
                </InputAdornment>
              )
            }}
          />
          <TextField
            fullWidth
            label="Password"
            name="password"
            style={{ marginTop: "1rem" }}
            type="password"
            variant="outlined"
            value={values.password}
            onChange={handleChange}
            onBlur={handleBlur}
            helperText={touched.password ? errors.password : ""}
            error={touched.password && Boolean(errors.password)}
            InputProps={{
              endAdornment: (
                <InputAdornment>
                  <LockIcon />
                </InputAdornment>
              )
            }}
          />
        </CardContent>

        <CardActions className={classes.loginButtonSection}>
          <Button
            type="submit" //<----------- see here
            color="primary"
            variant="contained"
            onClick={signIn}
            className={classes.loginButton}
            disabled={isSubmitting}
          >
            Log In
          </Button>
        </CardActions>
      </form>
    </Card>
  );
};

let yup = require("yup");

const Form = withFormik({
  mapPropsToValues: ({ username, password }) => {
    return {
      username: username || "",
      password: password || ""
    };
  },

  validationSchema: yup.object().shape({
    username: yup.string().required("Required"),
    password: yup
      .string()
      .min(8, "Password must contain at least 8 characters")
      .required("Enter your password")
  }),

  handleSubmit: (values, { setSubmitting }) => {
    setTimeout(() => {
      // submit to the server
      alert(JSON.stringify(values, null, 2));
      setSubmitting(false);
    }, 1000);
  }
})(LoginForm);

LoginForm.propTypes = {
  className: PropTypes.string
};

// export default LoginForm(useStyles)(Form);
export default Form;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM