完全获取数据后加载状态更改

时间:2018-01-24 20:20:26

标签: javascript reactjs redux react-redux redux-thunk

我有动作创建者从API获取数据,并有另一个动作创建者用于加载状态,并希望在完全获取数据时更改加载状态。

现在,我编写了以下代码但效果不佳,在完全提取数据之前将状态更改为false。

我的ActionCreator:

export const loadingStatus = (bool) => {
    return {
        type: Constants.LOADING_STATUS,
        isLoading: bool
    };
}
const allFlashCards = (action) => {
    return{
        type: Constants.ALL_CARD,
        ...action
    }
};

export const fetchAllFlashCards = () => {
    return (dispatch) => {
        dispatch(loadingStatus(true));
        return axios.post(API.DISPLAY_ALL_CARDS)
            .then((data)=>{
                console.warn(data);
                dispatch(allFlashCards(data));
                dispatch(loadingStatus(false));
            }).catch((error)=>{
                console.warn(error)
            });
    }
};

和我的减速机:

const FlashCard = (state = [], action) => {
    switch (action.type) {
        case Constants.ADD_CARD:
            return {...state, data: action.data};
            break;
        case Constants.ALL_CARD:
            return {...state, data: action};
            break;
        default:
            return state;
    }
};

export const Loading = (status= false, action) => {
    switch (action.type) {
        case Constants.LOADING_STATUS:
            return action.isLoading;
            break;
        default:
            return status;
    }
}

在我的组件中:

componentDidMount() {
    this.props.fetchCards();
}

render() {
    return(
        <div>
            {this.props.loading ?
                    <Loading/> :
                    Object.keys(this.props.cards.data).map(this.renderCard)
                }
        </div>
    );
}

const mapStateToProps = (state) => ({
    cards: state.main,
    loading: state.loading
});
const mapDispatchToProps = (dispatch) => ({
    fetchCards: bindActionCreators(fetchAllFlashCards, dispatch)
});

和combineReducer是:

import { combineReducers } from 'redux';
import FlashCard , { Loading } from './FlashCard.js';
import { routerReducer } from "react-router-redux";

export default combineReducers({
    main: FlashCard,
    loading: Loading,
    routing: routerReducer
});

在我的页面中,我在控制台中出错,它是: Uncaught TypeError: Cannot read property 'data' of undefined如果我的代码在超时时修复我的错误:/

我该怎么办?

2 个答案:

答案 0 :(得分:1)

您的默认状态是错误的:

const FlashCard = (state = [], action) => {
    switch (action.type) {
        case Constants.ADD_CARD:
            return {...state, data: action.data};
            break;
        case Constants.ALL_CARD:
            return {...state, data: action};
            break;
        default:
            return state;
    }
};

它应该是一个空对象{}而不是一个空数组[],因为你要返回对象。

此代码

export const fetchAllFlashCards = () => {
    return (dispatch) => {
        dispatch(loadingStatus(true));
        return axios.post(API.DISPLAY_ALL_CARDS)
            .then((data)=>{
                console.warn(data);
                dispatch(allFlashCards(data));
                dispatch(loadingStatus(false));
            }).catch((error)=>{
                console.warn(error)
            });
    }
};

看起来完全没问题。在设置闪存卡之前,不应调用loadingStatus(false)。您的减速器和动作创建器是同步的(应该如此)。所以,没有什么值得注意的。

我看到您在action.data操作案例中使用Constants.ADD_CARD,但在您的代码中,您不会发送任何具有该类型的操作。你在其他地方做到了吗?也许错误在哪里?

编辑:

您使用.data的另一个地方是您的渲染器:this.props.cards.datastate.main的价值是什么? 你是如何创建rootReducer的?它应该是这样的:

const rootReducer = combineReducers({
  main: FlashCard,
  loading: Loading,
});

你在那里使用main吗?或者也许是cards

答案 1 :(得分:0)

最后,我解决了我的问题:

在我的actionCreator中,将fetchAllFlashCards方法更改为以下内容:

export const fetchAllFlashCards = () => {
    return (dispatch) => {
        dispatch(loadingStatus(true));
        return axios.post(API.DISPLAY_ALL_CARDS)
            .then(({data})=>{
                dispatch(allFlashCards(data));
                dispatch(loadingStatus(false));
            }).catch((error)=>{
                console.warn(error)
            });
    }
};

并在reducer中将FlashCard减速器更改为以下内容:

const FlashCard = (state = [], action) => {
    switch (action.type) {
        case Constants.ADD_CARD:
            return {...state, data: action.data};
            break;
        case Constants.ALL_CARD:
            return {...state, data: action.data};
            break;
        default:
            return state;
    }
};