Reputation: 313
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
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