Как отправить действие asyn c в Redux с помощью Redux Thunk: TypeError: невозможно прочитать свойство 'loading' неопределенного значения - PullRequest
0 голосов
/ 18 июня 2020

Я установил все на стороне Redux и вижу каждое действие в Redux Devtool. Работает все идеально. Проблема возникает, когда я хочу отправить действие в React Component. В компоненте входа я хочу отправить действие, дождаться его ответа, а затем в зависимости от ответа перенаправить его на страницу или показать ошибки. Вот мои коды:

userActions. js

import axios from "axios";
import {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILED,
} from "./types";

const loginUserRequest = () => {
  return {
    type: LOGIN_USER,
  };
};

const loginUserSuccess = (user) => {
  return {
    type: LOGIN_USER_SUCCESS,
    payload: user,
  };
};

const loginUserFailed = (error) => {
  return {
    type: LOGIN_USER_FAILED,
    payload: error,
  };
};

export const loginUser = (dataSubmitted) => {
  return (dispatch) => {
    dispatch(loginUserRequest());
    axios
      .post("/api/users/login", dataSubmitted)
      .then((response) => {
        dispatch(loginUserSuccess(response.data));
      })
      .catch((err) => {
        dispatch(loginUserFailed(err));
      });
  };
};

userReducer. js:

import {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILED,
} from "../actions/types";

const initialState = {
  loading: false,
  user: "",
  error: "",
};

export default function (state = initialState, action) {
  switch (action.type) {
    case LOGIN_USER:
      return { ...state, loading: true };

    case LOGIN_USER_SUCCESS:
      return { ...state, loading: false, user: action.payload, error: "" };

    case LOGIN_USER_FAILED:
      return { ...state, loading: false, user: "", error: action.payload };

    default:
      return state;
  }
}

Приведенные выше коды отлично работают и делают свою работу. Проблема заключается в следующем коде, в котором я отправляю действие asyn c. После запуска кода я получаю this.props.userData как undefined.

Login. js

import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { loginUser } from "../../actions/userActions";

export class Login extends Component {
  state = {
    email: "",
    password: "",
    errors: [],
  };

  displayErrors = (errors) =>
    errors.map((error, i) => (
      <div className="alert alert-danger" key={i}>
        {error}
      </div>
    ));

  handleSubmit = (e) => {
    e.preventDefault();
    var { email, password } = this.state;
    var errors = [];

    if (email === "") {
      errors.push("Email is required");
    }

    if (password === "") {
      errors.push("Password is required");
    }

    this.setState({ errors: errors });
    //Problem occurs here
    this.props.dispatch(loginUser({ email, password }));

    if (response.payload.success) {
      sessionStorage.setItem("jwt", response.payload.token);
      sessionStorage.setItem("userId", response.payload._id);
      this.props.history.push("/");
    } else {
      errors.push("Username and/or Password is not correct");
      this.setState({ errors: errors });
    }
  };

  render() {
    return (
      <form className="form-signin" onSubmit={this.handleSubmit}>
        <h1 className="h3 mb-3 font-weight-normal">Sign in</h1>

        {this.state.errors.length > 0 && this.displayErrors(this.state.errors)}
        <label for="inputEmail" className="sr-only">
          Email address
        </label>
        <input
          type="email"
          id="inputEmail"
          className="form-control"
          placeholder="Email address"
          value={this.state.email}
          onChange={(e) => {
            this.setState({ email: e.target.value });
          }}
          required
          autoFocus
        />
        <label for="inputPassword" className="sr-only">
          Password
        </label>
        <input
          type="password"
          id="inputPassword"
          className="form-control"
          placeholder="Password"
          value={this.state.password}
          onChange={(e) => {
            this.setState({ password: e.target.value });
          }}
          required
        />
        <div className="checkbox mb-3">
          <label>
            <input type="checkbox" value="remember-me" /> Remember me
          </label>
        </div>
        <button
          className="btn btn-lg btn-primary btn-block"
          type="submit"
          onClick={this.handleSubmit}
        >
          Sign in
        </button>
        <Link to="/register">Sign Up</Link>
      </form>
    );
  }
}

function mapStateToProps(state) {
  return {
    userData: state.user,
  };
}

export default connect(mapStateToProps)(Login);

1 Ответ

0 голосов
/ 18 июня 2020

Вам необходимо установить connected-react-router, чтобы управлять историей внутри redux:

import { push } from 'connected-react-router';

export const loginUser = (dataSubmitted) => {
  return (dispatch) => {
    dispatch(loginUserRequest());
    axios
      .post("/api/users/login", dataSubmitted)
      .then((response) => {
        dispatch(loginUserSuccess(response.data));

        if (response.payload.success) {
          sessionStorage.setItem("jwt", response.payload.token);
          sessionStorage.setItem("userId", response.payload._id);
          push("/");
        } else {
          errors.push("Username and/or Password is not correct");
        }
      })
      .catch((err) => {
        dispatch(loginUserFailed(err));
      });
  };
};
...