开发者问题收集

如何解决 React 身份验证中未捕获的(在 Promise 中)TypeError?

2019-06-26
2797

我对 MERN 堆栈还很陌生。我正在尝试使用 jwt 设置用户身份验证。 问题仅在我使用前端登录时发生。当我使用 POST man 发出 http 请求时,登录成功 但是当我使用电子邮件和密码登录时,我收到以下错误:

console

Uncaught (in promise) TypeError: Cannot read property 'data' of undefined
at authActions.js:40

我知道它显示了错误的位置,但我仍然无法修复它。

authActions.js

import axios from "axios";
import setAuthToken from "../utils/setAuthToken";
import jwt_decode from "jwt-decode";

import { GET_ERRORS, SET_CURRENT_USER, USER_LOADING } from "./types";

// Register User
export const registerUser = (userData, history) => dispatch => {
  axios
    .post("/api/users/register", userData)
    .then(res => history.push("/login")) // re-direct to login on successful register
    .catch(err =>
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      })
    );
};

// Login - get user token
export const loginUser = userData => dispatch => {
  axios
    .post("/api/users/login", userData)
    .then(res => {
      // Save to localStorage

      // Set token to localStorage
      const { token } = res.data;
      localStorage.setItem("jwtToken", token);
      // Set token to Auth header
      setAuthToken(token);
      // Decode token to get user data
      const decoded = jwt_decode(token);
      // Set current user
      dispatch(setCurrentUser(decoded));
    })
    .catch(err =>
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      })
    );
};

// Set logged in user
export const setCurrentUser = decoded => {
  return {
    type: SET_CURRENT_USER,
    payload: decoded
  };
};

// User loading
export const setUserLoading = () => {
  return {
    type: USER_LOADING
  };
};

// Log user out
export const logoutUser = () => dispatch => {
  // Remove token from local storage
  localStorage.removeItem("jwtToken");
  // Remove auth header for future requests
  setAuthToken(false);
  // Set current user to empty object {} which will set isAuthenticated to false
  dispatch(setCurrentUser({}));
};

以下是我的登录前端代码。

login.jsx

class Login extends Component {
  constructor(props) {
    super(props);

    this.state = {
      email: "",
      password: ""
    };
  }
  componentDidMount() {
    // If logged in and user navigates to Login page, should redirect them to dashboard
    if (this.props.auth.isAuthenticated) {
      this.props.history.push("/dashboard");
    }
  }
  validateForm() {
    return this.state.email.length > 0 && this.state.password.length > 0;
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.auth.isAuthenticated) {
      this.props.history.push("/dashboard"); // push user to dashboard when they login
    }

    if (nextProps.errors) {
      this.setState({
        errors: nextProps.errors
      });
    }
  }

  handleChange = event => {
    this.setState({
      [event.target.id]: event.target.value
    });
  };

  handleSubmit = event => {
    event.preventDefault();
    console.log("Submit called");
    const userData = {
      email: this.state.email,
      password: this.state.password
    };

    this.props.loginUser(userData);
  };

  render() {
    const errors = this.state;
    return (
      <div className="Login">
        <form onSubmit={this.handleSubmit}>
          <FormGroup controlId="email" bs="large">
            <FormLabel>Email</FormLabel>
            <span className="red-text">{errors.emailnotfound}</span>
            <FormControl
              autoFocus
              type="email"
              value={this.state.email}
              onChange={this.handleChange}
              className={classnames("", {
                invalid: errors.email || errors.emailnotfound
              })}
            />
          </FormGroup>
          <FormGroup controlId="password" bs="large">
            <FormLabel>Password</FormLabel>
            <span className="red-text">
              {errors.password}
              {errors.passwordincorrect}
            </span>
            <FormControl
              value={this.state.password}
              onChange={this.handleChange}
              type="password"
              className={classnames("", {
                invalid: errors.password || errors.passwordincorrect
              })}
            />
          </FormGroup>
          <Button
            block
            bs="large"
            disabled={!this.validateForm()}
            type="submit"
          >
            Login
          </Button>
          <br />
          <p> Dont have account ? </p>
          <Link to="/register">
            {" "}
            <p style={{ color: "blue" }}> Join Us </p>{" "}
          </Link>
        </form>
        <br />
      </div>
    );
  }
}

我省略了一些导入语句以缩短代码。

3个回答

错误出现在第 40 行,位于 payload: err.response.data 中。

如果显示

Cannot read property 'data' of undefined

则表示 err.responsendefined

在传递该信息之前,您应该进行一些检查。也许它返回的是没有 .response 的其他错误。

尝试 console.log(err) 来检查其中的内容。

Vencovsky
2019-06-26

看来您在发送数据之前没有对其进行字符串化。需要 qs 库并将代码更改为:

axios
.post("/api/users/register", qs.stringify( userData ))
.then(res => history.push("/login")) // re-direct to login on successful register
.catch(err =>
  dispatch({
    type: GET_ERRORS,
    payload: err.response.data
  })
);

您还可以通过查看浏览器开发工具中的 Network 选项卡来检查数据是否发送正确。我预计数据发送格式错误。我希望我没猜错。

Marios Simou
2019-06-26

您需要将代码从

onSubmit={this.handleSubmit 更新为 onSubmit={()=>this.handleSubmit()

并将

onChange={this.handleChange 更新为 onChange={()=>this.handleChange()

因此,您的密码和电子邮件未设置为状态,并且您的 API axios.post("/api/users/login", userData) 引发异常。

paragxviii
2019-06-26