【问题标题】:Is this the correct way to make an axios GET request with react redux?这是使用 react redux 发出 axios GET 请求的正确方法吗?
【发布时间】:2020-09-30 23:00:17
【问题描述】:

我是初学者,所有这些都是非常新的。我已经调试了一段时间,我似乎无法修复这个错误。我会很感激一些指示。

其他帖子和放置请求正在工作,但是当我尝试执行获取请求时出现代理错误(无法从 localhost:3000 代理请求 /api/users/userdata 到 http://localhost:5000/。(ECONNREFUSED)) .

这是使用 React Developer Tools 组件选项卡在 Home 中的 props 的 sn-p:
props of Home

redux 的操作类型:client\src\actions\types.js

export const GET_ERRORS = "GET_ERRORS";

export const USER_LOADING = "USER_LOADING";
export const SET_CURRENT_USER = "SET_CURRENT_USER";

export const GET_USERDATA = "GET_USERDATA";
export const UPDATE_USERDATA = "UPDATE_USERDATA";

redux 的操作:client\src\actions\userdataActions.js

import axios from "axios";

import {
    GET_ERRORS,
    GET_USERDATA,
    UPDATE_USERDATA
} from "./types";

// Get userdata with username
export const getUserData = (userData) => dispatch => {
    return axios
        .get("/api/users/userdata", userData)
        .then(response => {
            dispatch(fetchUserData(response.data)); 
        })
        .catch(err => {
            dispatch(getErrors(err));
        });
};

// Put new userdata with username
export const updateUserData = (newUserData) => dispatch => {
    axios
        .put("/api/users/userdata", newUserData)
        .then(response => {
            dispatch(updatingUserData());
        })
        .catch(err => {
            dispatch(getErrors(err));
        });
};

export const fetchUserData = userData => {
    return {
        type: GET_USERDATA,
        payload: userData
    }
};

export const updatingUserData = () => {
    return {
        type: UPDATE_USERDATA
    };
};

// Get Errors 
export const getErrors = err => {
    return {
      type: GET_ERRORS,
      payload: err.response.data
    };
};

redux 的减速器:client\src\reducers\dataReducers.js

import {
    GET_USERDATA, 
    UPDATE_USERDATA
} from "../actions/types";

const isEmpty = require("is-empty");

const initialState = {
    hasUserData: false,
    user: {},
    updated: false,
};

export default function(state = initialState, action) {
    switch (action.type) {
        case GET_USERDATA:
            return {
                ...state,
                hasUserData: !isEmpty(action.payload),
                user: action.payload
            };
        case UPDATE_USERDATA:
            return {
                ...state,
                updated: true,
            };
        default:
            return state;
    }
}

使用 react 的前端:client\src\components\home\Home.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { logoutUser } from "../../actions/authActions";
import { getUserData, updateUserData } from "../../actions/userdataActions";

import Logout from "./Logout.js";
import Coins from "./Coins.js";
import Happiness from "./Happiness.js";

class Home extends Component {
    constructor(props) {
        super(props);
        this.name = this.props.auth.user.name;
        this.updateCoins = this.updateCoins.bind(this);
        this.updateHappiness = this.updateHappiness.bind(this);
    }

    componentDidMount() {
        if (!this.props.userdata.hasUserData) {
            const userData = { name: this.name };
            this.props.getUserData(userData); 
        }  
    }

    onLogoutClick = e => {
        e.preventDefault();
        this.props.logoutUser();
    };    

    updateCoins(newCoins) {
        const userData = {
            name: this.name,
            coins: newCoins,
        };
        this.props.updateUserData(userData); 
    }

    updateHappiness(newHappiness) {
        const userData = {
            name: this.name,
            happiness: newHappiness,
        };
        this.props.updateUserData(userData); 
    }

    render() {
        return (
            <div>  
                <Coins coins={this.props.userdata.user.coins} updateCoins={this.updateCoins} />
                <Happiness happiness={this.props.userdata.user.happiness} updateHappiness={this.updateHappiness} />
                <Logout onLogoutClick={this.onLogoutClick} />           
            </div>
        );
    }
}

Home.propTypes = {
    logoutUser: PropTypes.func.isRequired,
    getUserData: PropTypes.func.isRequired,
    updateUserData: PropTypes.func.isRequired,
    auth: PropTypes.object.isRequired,
    errors: PropTypes.object.isRequired,
    userdata: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
    auth: state.auth,
    errors: state.errors,
    userdata: state.userdata
});

export default connect(
    mapStateToProps,
    { logoutUser,
      getUserData,
      updateUserData }
)(Home);

【问题讨论】:

    标签: reactjs react-redux axios redux-thunk


    【解决方案1】:

    我不会使用这样的 ajax 服务。而是

    1. 使用服务模块封装所有ajax调用并处理异常。这些服务的结果是带有原始数据的 Promise

    2. 在您的 thunk 操作中,然后使用服务获取数据并在必要时调度以更新存储

    3. 组件只是像往常一样使用 thunk 操作。 这有助于增加关注点的分离,更容易测试和维护。

    
    const handleError = (error) => {
       console.log(error);
    };
    
    export const getUserData = (userData) => {
        return axios
            .get("/api/users/userdata", userData)
            .then(response => (response.data))
            .catch(err => {
                handleError(err);
            });
    };
    
    ...
    // later in thunk action creator 
    
    const updateUserDataThunk = async (userData) => dispatch => {
        const apiData = await getUserData(userData);
        dispatch(updateUser(apiData));
    }
    
    ...
    // in component
    
    componentDidMount(){
      dispatch(updateUserDataThunk(this.props.userData));
    }
    
    

    【讨论】:

    • 你能把它放到代码中吗?
    • 你能解释一下为什么你选择使用 async await 来执行 thunk 操作而不是 Promise 吗?
    • 我还想将错误发送到前端以显示它。我怎么能用这个修改后的代码结构来做到这一点?
    • 对于promise,我认为async提供了一种更简洁的方式来推理代码,你可以使用promise,它可以产生相同的结果对于将错误发送到前端显示,服务可以为apiData 可以包含一些规范化的错误消息。通常我认为我们不需要显示原始网络错误消息。
    • 感谢 cmets!我会试试看。
    最近更新 更多