简体   繁体   English

如何在反应 redux 中发送来自 api 的响应数据?

[英]How to dispatch response data from api on action in react redux?

I'm currently working on an e-commerce project and we are using react-redux.我目前正在做一个电子商务项目,我们正在使用 react-redux。 But I'm having a problem with returning a response from API instances using Axios request call on the action for Login with Jwt module.但是我在使用 Axios 请求调用 Jwt 模块的登录操作从 API 实例返回响应时遇到问题。

This is Axios file that consists of base URLs and instances.这是包含基本 URL 和实例的 Axios 文件。

api/lib/axios.js: api/lib/axios.js:

/* eslint-disable no-nested-ternary */
import axios from "axios"
import { store } from "../../redux/store"
import { REFRESH_TOKEN } from "../../redux/auth/constant"
import Environment from "./environment"

const axiosInstance = axios.create({
  baseURL: Environment.BASE_URL,
  headers: {
    Authorization: localStorage.getItem("access")
      ? `JWT${localStorage.getItem("access")}`
      : "none",
    "Content-Type": "application/json",
    accept: "application/json"
  }
})

axiosInstance.interceptors.response.use(
  (response) => response,
  (error) => {
    const originalRequest = error.config

    if (
      error.response.status === 401 &&
      error.response.statusText === "Unauthorized"
    ) {
      const body = store.getState().auth.token.refresh
      return axiosInstance
        .post("api/token/refresh/", { refresh: body })
        .then((response) => {
          store.dispatch({
            type: REFRESH_TOKEN,
            payload: response.data
          })
          axiosInstance.defaults.headers.Authorization = `JWT ${response.data.access}`
          originalRequest.headers.Authorization = `JWT ${response.data.access}`

          return axiosInstance(originalRequest)
        })
    }
    return Promise.reject(error)
  }
)

export default axiosInstance

Here is also an environment file where all our environment variables are stored.这也是一个环境文件,其中存储了我们所有的环境变量。

api/lib/environment.js: api/lib/environment.js:

const Environment = {
  BASE_URL: "http://babylandworld.com:8000/"
}

export default Environment

I'm calling an API request from auth file inside api/lib/auth as:我从 api/lib/auth 中的 auth 文件调用 API 请求:

api/lib/auth.js: api/lib/auth.js:

/* eslint-disable import/prefer-default-export */
import axiosInstance from "./axios"
// Auth Request from backend api using axios
const auth = async (username, password) => {
  const body = { username, password }
  const response = await axiosInstance
    .post(`/api/token/obtain/`, body)
    .then((res) => {
      axiosInstance.defaults.headers.Authorization = `JWT ${res.data.access}`
    })
  return response
}
export { auth }

I have dispatch the response from the api/auth.js file to auth/action.js.我已将 api/auth.js 文件的响应发送到 auth/action.js。 But I'm getting an error on dispatch and catch with no user data after submitting the login form.但是在提交登录表单后,我在发送和捕获时遇到错误,没有用户数据。

Here is action.js code: auth/action.js:这是 action.js 代码: auth/action.js:

import * as constants from "./constant"

import { auth } from "../../api/lib/auth"

const loginBegin = () => ({
  type: constants.LOGIN_BEGIN
})
const login = ({ username, password }) => (dispatch) => {
  dispatch({
    type: constants.LOGIN_SUCCESS,
    paylaod: auth(username, password).data
  }).catch(() =>
    dispatch({
      type: constants.LOGIN_FAIL
    })
  )
}

export { loginBegin, login }

Also, I have created actions types in constant.js file as:另外,我在 constant.js 文件中创建了动作类型:

auth/constant.js: auth/constant.js:

export const REFRESH_TOKEN = "REFRESH_TOKEN"
export const LOGIN_BEGIN = "LOGIN_BEGIN"
export const LOGIN_SUCCESS = "LOGIN_SUCCESS"
export const LOGIN_FAIL = "LOGIN_FAIL"
export const AUTH_ERROR = "AUTH_ERROR"
export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS"

Here is reducer file as: auth/reducer.js:这是减速器文件: auth/reducer.js:

import { actions } from "react-table"
import * as constants from "./constant"

const initialState = {
  token: localStorage.getItem("token"),
  isAuthenticated: null,
  isLoading: false,
  user: null
}
function authReducer(state = initialState, action) {
  switch (action.type) {
    case constants.LOGIN_BEGIN:
      return {
        ...state,
        isAuthenticated: false,
        isLoading: true,
        user: ""
      }
    case constants.LOGIN_SUCCESS:
      return {
        ...state,
        ...action.payload,
        isAuthenticated: true,
        isLoading: false
      }
    case constants.LOGIN_FAIL:
    case constants.LOGOUT_SUCCESS:
      return {
        ...state,
        token: null,
        isAuthenticated: false,
        user: null,
        isLoading: false
      }
    default:
      return state
  }
}
export default authReducer

This is our login page component as: pages/auth/loginTabset.js:这是我们的登录页面组件: pages/auth/loginTabset.js:

/* eslint-disable jsx-a11y/anchor-has-content */
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, { Component } from "react"

import PropTypes from "prop-types"
import { connect } from "react-redux"
import { Redirect } from "react-router-dom"
import { login } from "../../redux/auth/action"

export class LoginTabset extends Component {
  state = {
    username: "",
    password: ""
  }

  clickActive = (event) => {
    document.querySelector(".nav-link").classList.remove("show")
    event.target.classList.add("show")
  }

  handleSubmit = (e) => {
    e.preventDefault()
    this.props.login(this.state.username, this.state.password)
  }

  handleChange = (e) => this.setState({ [e.target.name]: e.target.value })

  render() {
    if (this.props.isAuthenticated) {
      return <Redirect to="/dashboard" />
    }
    const { username, password } = this.state
    return (
      <div>
        <h4 className="text-center">Login Panel</h4>
        <hr />
        <form
          className="form-horizontal auth-form"
          onSubmit={this.handleSubmit}>
          <div className="form-group">
            <input
              required=""
              name="username"
              value={username}
              type="text"
              className="form-control"
              placeholder="Username"
              id="username"
              onChange={this.handleChange}
            />
          </div>
          <div className="form-group">
            <input
              required=""
              name="password"
              value={password}
              type="password"
              className="form-control"
              placeholder="Password"
              id="password"
              onChange={this.handleChange}
            />
          </div>
          <div className="form-terms">
            <div className="custom-control custom-checkbox mr-sm-2">
              <input
                type="checkbox"
                className="custom-control-input"
                id="customControlAutosizing"
              />
              <label className="d-block" htmlFor="chk-ani2">
                <input
                  className="checkbox_animated"
                  id="chk-ani2"
                  type="checkbox"
                />
                Reminder Me{" "}
                <span className="pull-right">
                  {" "}
                  <a href="#" className="btn btn-default forgot-pass p-0">
                    lost your password
                  </a>
                </span>
              </label>
            </div>
          </div>
          <div className="form-button">
            <button className="btn btn-primary" type="submit">
              Login
            </button>
          </div>
          <div className="form-footer">
            <span>Or Login up with social platforms</span>
            <ul className="social">
              <li>
                <a className="fa fa-facebook" href="" />
              </li>
              <li>
                <a className="fa fa-twitter" href="" />
              </li>
              <li>
                <a className="fa fa-instagram" href="" />
              </li>
              <li>
                <a className="fa fa-pinterest" href="" />
              </li>
            </ul>
          </div>
        </form>
      </div>
    )
  }
}
LoginTabset.propTypes = {
  login: PropTypes.func.isRequired,
  isAuthenticated: PropTypes.bool.isRequired
}

const mapStateToProps = (state) => ({
  isAuthenticated: state.auth.isAuthenticated
})
export default connect(mapStateToProps, { login })(LoginTabset)

Problem: when submitting the login form, there is an error on dispatch an action from api/lib/auth and don't get any response data from the API server.问题:提交登录表单时,从 api/lib/auth 发送操作时出错,并且没有从 API 服务器获得任何响应数据。

Please, anyone, help to solve this problem as soon as possible.请任何人帮助尽快解决这个问题。

dispatch function doesn't return you a promise to use. dispatch function 不会返回 promise 来使用。 You must instead call the auth function and wait on it before firing dispatch since it an async function.您必须改为调用 auth function 并在触发调度之前等待它,因为它是异步 function。

You can use async-await with try catch like below您可以将 async-await 与 try catch 一起使用,如下所示

const login = ({ username, password }) =>async (dispatch) => {

  try {
     const res = await auth(username, password);
     dispatch({
       type: constants.LOGIN_SUCCESS,
       paylaod: res.data,
     })
  } catch(error ) {
    dispatch({
      type: constants.LOGIN_FAIL
    });
  }
}

export { loginBegin, login }

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

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