Изменение статуса загрузки после получения данных полностью

У меня есть создатель действий для получения данных из 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)
});

и объединить редуктор это:

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 ответа

Решение

Наконец я исправил свою проблему:

В моем 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)
            });
    }
};

а в редукторе поменяй редуктор 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;
    }
};

Ваше состояние по умолчанию здесь неверно:

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.data, Какова ценность state.main? Как вы создаете свой rootReducer? Это должно быть что-то вроде этого:

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

Ты используешь main там? Или, может быть cards?

Другие вопросы по тегам