New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deduplicate request if isFetching in Saga world #830
Comments
You can make a convention in your app.
And
|
instead
After action 'FETCH_START' set isFetching to true in store. Don't forget after action 'FETCH_SUCCESS' and 'FETCH_FAILURE' set isFetching to false |
Also it might be a good to decouple your saga from the state shape itself, im alway trying to do this, unless it would provide to copying reducers' logic in your sagas. You could create a higher order saga for this, which would look something like this: function* takeOneAndBlock(pattern, worker, ...args) {
const task = yield fork(function* () {
while (true) {
const action = yield take(pattern)
yield call(worker, ...args, action)
}
})
return task
} and use it like this: function* fetchRequest() {
try {
yield put({type: 'FETCH_START'});
const res = yield call(api.fetch);
yield put({type: 'FETCH_SUCCESS'});
} catch (err) {
yield put({type: 'FETCH_FAILURE'});
}
}
yield takeOneAndBlock('FETCH_REQUEST', fetchRequest) In my opinion this way is far way more elegant and also its behaviour can be easily customized depending on your needs. |
@Andarist for exmaple, I want to fetch todo list, I got three todo list, 'all' 'active' 'completed', I think a lot from your code.
code line ** 1 ** It is a large conflict in my design if the recommend saga way is used... So, I try to control my request out of saga, write the business logic directly in container component. I wonder there is a better practice to implement what i want in Saga way? |
Thanks for replying To @UchihaVeha So, i must use another action.type such as 'LOAD_PRODUCT' @lovio pointed. To @lovio |
Well, this can really be solved in numerous ways.
function* customTake(pattern, worker, ...args) {
let currentTasks = {};
const task = yield fork(function* () {
while (true) {
const action = yield take(pattern)
const { filter } = action;
if ( !currentTasks[filter] ) {
currentTasks[filter] = yield fork(worker, ...args, currentTasks, action)
currentTasks[filter] = null
}
}
})
return task
}
function* fetchRequest(currentTasks, action) {
try {
yield put({type: 'FETCH_START'});
const res = yield call(api.fetch);
yield put({type: 'FETCH_SUCCESS'});
} catch (err) {
yield put({type: 'FETCH_FAILURE'});
} finally {
currentTasks[action.filter] = null
}
}
yield customTake('FETCH_REQUEST', fetchRequest)
function* customTake(pattern, worker, ...args) {
let currentTasks = {};
const task = yield fork(function* () {
yield takeEvery(pattern, function* () {
if (currentTasks[filter]) {
return
}
yield call(worker, ...args, action)
})
yield takeEvery([FETCH_SUCCESS, FETCH_FAILURE], function* (action) {
currentTasks[action.filter] = null
})
})
return task
}
function* fetchRequest(currentTasks, action) {
try {
yield put({type: 'FETCH_START', filter: action.filter});
const res = yield call(api.fetch);
yield put({type: 'FETCH_SUCCESS', filter: action.filter});
} catch (err) {
yield put({type: 'FETCH_FAILURE', filter: action.filter});
}
}
yield customTake('FETCH_REQUEST', fetchRequest)
function* takeOneAndBlock(pattern, worker, ...args) {
const task = yield fork(function* () {
while (true) {
const action = yield take(pattern)
yield call(worker, ...args, action)
}
})
return task
}
function* fetchRequest() {
try {
yield put({type: 'FETCH_START'});
const res = yield call(api.fetch);
yield put({type: 'FETCH_SUCCESS'});
} catch (err) {
yield put({type: 'FETCH_FAILURE'});
}
}
yield takeOneAndBlock(action => action.type === 'FETCH_REQUEST' && action.filter === 'all', fetchRequest)
yield takeOneAndBlock(action => action.type === 'FETCH_REQUEST' && action.filter === 'active', fetchRequest)
yield takeOneAndBlock(action => action.type === 'FETCH_REQUEST' && action.filter === 'completed', fetchRequest) and possibly many more, just using 3 top of my head |
@Andarist Thanks a lot! The solustions are impressive. which gives me a way to control the entry of worker saga. instead of control the most first request like 'FETCH_REQUEST' in redux-thunk way. |
actionChannel doesn't resolve that? |
I'm wondering the same thing. It appears that it does. |
HI, guys. I got a problem to use saga instead of thunk functions.
Imaging a simple fetch action. I want fetch something and no more duplicate request if
isFetching
.In thunk world, I can totally control my whole process of dispatch, which mean the 'FETCH_REQUEST' is also controlled.
but in saga world, the 'FETCH_REQUEST' is a entry of work saga,
Here is the problem, I try to "filter" my every 'FETCH_REQUEST' in my work saga to control workflow, but it will be harder in real world application, since other arguments specified in fetch function.
Can i have some trick, to control the 'FETCH_REQUEST' thing, just like thunk examples???
Anything helpful is welcomed 😀
The text was updated successfully, but these errors were encountered: