Action from an http requetis fired twice
dbertella opened this issue · 3 comments
I have a component that at componentDidMount
will fire an action that makes an http request.
What I want is to set an isFetching
flag in the reducer.
Everything works as expected the first time I load the component, but the second the flag isFetching
is never set to true
.
I played just a little with the middleware during this weekend so I'm not really sure why I have this problem.
This is my main
, I just readapted the code from one of the example.
const fetchPostById = (sources) => {
const post$ = sources.ACTION
.filter(action => action.type === ActionTypes.POST_REQUESTED)
.map(action => action.postId);
const request$ = post$
.map(postId => ({
url: `${BASE_URL}posts/${postId}`,
category: 'post'
}));
const response$ = sources.HTTP
.select('post')
.flatten();
const action$ = xs.combine(post$, response$)
.map(arr => actions.receivePostById(arr[0], arr[1].body));
return {
ACTION: action$,
HTTP: request$
}
}
And this is the reducer:
const post = (state = initialPost, action) => {
switch (action.type) {
case 'POST_REQUESTED':
return {
...state,
isFetching: true,
};
case 'POST_RECEIVED':
return {
...state,
isFetching: false,
[action.postId]: action.post,
};
default:
return state;
}
};
If I log what's going on with my request, I can see that isFetching
is false at the beginning, then the action POST_REQUESTED
is fired and isFetching
is set to true. When POST_RECEIVED
is being fired (from the cycle code) isFetching
goes back to false. That's the normal case.
On the next time POST_RECEIVED
is being fired two times for the same action and isFetching
flag is never set to true
.
You can see an online version here https://dbertella.github.io/food-and-quote/ in case.
Am I missing something?
The problem is with the use of combine: https://github.com/staltz/xstream#-combinestream1-stream2
The second time you call the POST_REQUESTED action from react, it's gonna emit POST_RECEIVED even without a response (because combine uses the latest response).
I think you may need sampleCombine instead (https://github.com/staltz/xstream/blob/master/EXTRA_DOCS.md#-samplecombinestreams) But make sure the source stream is the response.
Hope it makes sense. Let me know if you can figure it out.
Thank you very much! I'll look into it and let you know!
Edit
I couldn't find the right way to make sampleCombine working instead, but I found out that in my case I don't need the combine at all, at least not for the single post.
const action$ = sources.HTTP
.select('post')
.flatten()
.map(res => actions.receivePostById(res.body.id, res.body));
That makes the trick, but I will have to understand better cycle for more advanced stuff anyway.
Thank you again!
Yeah if you don't need the post info in the stream, then you don't need combine 😃
Anyway in case you need the post this should work:
import sampleCombine from 'xstream/extra/sampleCombine'
const action$ = response$
.compose(sampleCombine(post$))
.map(([ response, post ]) => actions.receivePostById(post, response.body))