Ad

React JS Reducer - Not Able To Do Anything With The Returned Payload, Only Able To Print

- 1 answer

I'm struggling with this issue for a few days straight now.

My reducer file:

import {ADD_REPORT, GET_REPORTS, GET_REPORTS_ERROR, GET_REPORTS_SUCCESS} from "./ReportActions";

export const INITIAL_STATE = {
    reports: [],
    isFetching: false,
    error: ''
};

export default function reportReducer(state = INITIAL_STATE, action) {
    switch (action.type) {
        case GET_REPORTS:
            return{
                ...state,
                isFetching: true,
                error: ''
            };
        case GET_REPORTS_SUCCESS: // This is the part it's about.
            return {
                ...state,
                isFetching: false,
                reports: action.payload.reports,
                count: action.payload.reports.length
            };
        case GET_REPORTS_ERROR:
            return {
                ...state,
                isFetching: false,
                error: action.payload.error
            };

        case ADD_REPORT:
            return {...state,
                reports: [...state.reportStore.payload,
                    {
                        id: action.report.id,
                        date: action.report.date,
                        city: action.report.city,
                        status: action.report.status
                    }]
            };
        default:
            return state;
    }
}

My output:

enter image description here

As you can see, I'm not able to do anything with action.payload.reports or it will become empty. The data is being fetched through React Saga, sent to the action and handled by the reducer. When using hardcoded mock data that's following it does work:

        case GET_REPORTS_SUCCESS:
            return {
                ...state,
                isFetching: false,
                reports: [{"id":14,"date":"24-10 13:28","city":"blabla","status":"unfixed"}],
                count: [{"id":14,"date":"24-10 13:28","city":"blabla","status":"unfixed"}].length
            };

I'd appreciate any help!

Ad

Answer

Problem solved!

Reporting back after researching what was wrong. The problem was that I returned an array before it was done fetching.

First I used yield call to make a fetch API request in another component, and use the result to work with. (ReportSagas.js)

//Warning: This is not the solution, I'm explaining my fault first!
import { takeLatest, all, call, put } from 'redux-saga/effects';

import ReportService from '../../api/ReportList';

import {GET_REPORTS, getReportsSuccess, getReportsError} from "./ReportActions";

export function* getReportsSaga() {
    try {
        console.log("ReportSagas.js -> getReportsSaga() Try {}");
        const data = yield call(ReportService.getReports);
        yield put(getReportsSuccess(data));
        return data;
    } catch(error) {
        console.log("ReportSagas.js -> getReportsSaga() Catch {}");
        yield put(getReportsError(error));
        return error;
    }
}

export function* watchGetReports() {
    yield all([takeLatest(GET_REPORTS, getReportsSaga)]);
}

The Fetch request looked like this. And as you can see, the "reports" array was outside the scope and I returned it before the fetch was even finished. (api/ReportList.js)

//Warning: This is not the solution, I'm explaining my fault first!
class ReportService {
    getReports = async () => {
        let reports = [];
        fetch('https://xxx/')
            .then(response => response.json())
            .then(function(jsonResp) {
                jsonResp.forEach(function(reportItem) {
                    let report = {id: reportItem, date: reportItem.date, city: reportItem.city, status: reportItem.status};
                    reports.push(report);
                });
            });

        return reports;
    }
}

export default new ReportService();

So the solution I simply came up with, is to make the fetch request within the Sagas file like this, and it works fine! (ReportSagas.js)

import { takeLatest, all, call, put } from 'redux-saga/effects';

import {GET_REPORTS, getReportsSuccess, getReportsError} from "./ReportActions";

export function* getReportsSaga() {
    try {
        console.log("ReportSagas.js -> getReportsSaga() Try {}");
        let data = yield fetch(`http://xxx/`);
        data = yield data.json();
        yield put(getReportsSuccess(data));
        return data;
    } catch(error) {
        console.log("ReportSagas.js -> getReportsSaga() Catch {}");
        yield put(getReportsError(error));
        return error;
    }
}

export function* watchGetReports() {
    yield all([takeLatest(GET_REPORTS, getReportsSaga)]);
}
Ad
source: stackoverflow.com
Ad