jm li
jm li

Reputation: 313

In Redux-saga, how to call a saga in one saga's fetch?

In my React app, there is a Saga calling backend API to retrieve some chart data. Please read the source code

function fetchData () {
    return fetch(`${config.base}dashboard_charts.json`)
    .then((response) => {

        if (response.status === 200) {
            return response.json();
        } else if (response.status === 403) {
             return 'logon';
        }
    });
}

function * getData (action) {
    try {
        const charts = yield call(fetchData);

        if (charts === 'logon') {
            yield logon();
        } else {
            yield put({ type: UPDATE_DASHBOARD_CHART, charts });
        }
    } catch (error) {
        yield put({ type: UPDATE_DASHBOARD_CHART, charts: [] });
    }
}

function * logon (action) {
    yield auth();
}

export default function * portfolio () {
    yield [
        takeEvery(FETCH_DASHBOARD_CHART, getData)
    ];
};

There is a checking against the http response status in the function fetchData, if the status is 200 then return the response directly. But if the server side returns 403, it means the client needs to be authenticated, thus the program will goes to auth() and perform logon.

However, the http response status code checking is somehow a general functionality applied to all API calls. So I don't want to repeat this kind of code in every saga. For this purpose, I wrote a service 'responseHandler' to group the response code checking inside like this:

export default function responseHandler (resp) {
    if (resp.status === 401 || resp.status === 403) {
        yield auth();
    } else if (resp.status === 200) {

    } else {
        console.log('error handling');
    }
};

And it will be called inside the the fetchData

return fetch(`${config.base}dashboard_charts.json`)
    .then((response) => {
        responseHandler(response);
    });

But this approach is never working. 'yield auth()' is invalid in the responseHandler.

Can anyone suggest how to better design the code for this case ?

Upvotes: 0

Views: 2703

Answers (1)

Vladislav Ihost
Vladislav Ihost

Reputation: 2187

Maybe it makes a sense to organize logic several?

First, the fetch-wrapper can be modified so that in case of origin of HTTP of a response code which doesn't meet expectation for formation of successful result, to execute transition to catch-section. It will allow to save the fetchData function in the form of pure Promise without entering of generator logic into it.

Secondly the essence of the auth and logon functions isn't especially clear. If by results of such action the form for login be generated, then realize it through appropriate redux action. If transition to other page is required, use react-redux-router.

function fetchData () {
        return fetch(`${config.base}dashboard_charts.json`).then(response => (
            (response.status === 200) ? response.json() : Promise.reject('logon')
        ));
    }

function* getData (action) {
    try {
        const charts = yield call(fetchData);
        yield put({ type: UPDATE_DASHBOARD_CHART, charts });
    } catch (error) {
        yield put({ type: UPDATE_DASHBOARD_CHART, charts: [] });
        if(error.message === 'logon') {
            yield put({ type: PERMORM_AUTORIZE });
        }
    }
}

export default function * portfolio () {
    yield [ takeEvery(FETCH_DASHBOARD_CHART, getData) ];
};

And is your logic is more complex, just use fork from redux-saga. It allows perform more complex tasks.

Upvotes: 3

Related Questions