I'm workign with React + Redux + Saga and what I have done so far works perfectly but I need to send data back after a (succeful call).
dispatch to route => sends back an ID => gets the ID
But it doesn't do it.
Route (express server):
axios.post( ...
return res.json(resAlbum);
My saga :
function* postSpotifyAlbum(obj) {
obj = {
method: "POST",
url: BASEurl,
params: {
token: obj.payload.token,
albumCode: obj.payload.albumCode,
albumGenres: obj.payload.albumGenres,
userCode: obj.payload.userCode,
},
};
try {
const spotifyCategories = yield call(axios, axiosCall(obj));
yield put({
type: "POST_SPOTIFY_ALBUMS_SUCCESS",
payload: JSON.parse(spotifyCategories.data),
});
return spotifyCategories.data;
} catch (error) {
console.log(error);
yield put({ type: "POST_SPOTIFY_ALBUMS_ERROR", payload: error });
}
}
Component:
const res = await dispatch(postSpotifyAlbums(obj));
if I console log the res I just get back Obj I just sent.
Question:
Is there any way to send something back from SAGA?
i.e. res gives me just inserted obj
Or there's no way so then I need to make a second call to the reducer to give me back the just inserted obj?
I repeat, everythig wortks perfectly from the dispatch till the reducer (I ommited to be shorter) I just would like to see if I can expand my SAGA knowledge
The returned value from calling dispatch
is just the action that you dispatched. Your saga will "take" this action and dispatch additional actions, but that is all considered independent. So your res
variable is just the original action postSpotifyAlbums(obj)
.
Or there's no way so then I need to make a second call to the reducer to give me back the just inserted obj?
Yes, you would need to have a useSelector
in the component that is listening for the posted value.
This is a lot easier to do with redux-thunk because the thunk middleware overrides the default behavior of dispatch
. When you dispatch a thunk (an action creator which is a function of dispatch
) then you get back the value that's returned by the thunk.
Any return value from the inner function will be available as the return value of dispatch itself. This is convenient for orchestrating an asynchronous control flow with thunk action creators dispatching each other and returning Promises to wait for each other's completion - docs
action
const postSpotifyAlbums = (payload) => async (dispatch) => {
dispatch({ type: "POST_SPOTIFY_ALBUMS_PENDING" });
const args = {
method: "POST",
url: BASEurl,
params: {
token: payload.token,
albumCode: payload.albumCode,
albumGenres: payload.albumGenres,
userCode: payload.userCode
}
};
try {
const spotifyCategories = await axios.request(args);
dispatch({
type: "POST_SPOTIFY_ALBUMS_SUCCESS",
payload: spotifyCategories.data
});
// we can customize the returned value here to anything!
return spotifyCategories.data;
} catch (error) {
console.log(error);
dispatch({ type: "POST_SPOTIFY_ALBUMS_ERROR", payload: error });
}
};
component
const doDispatch = async () => {
// we get back whatever we specifically returned in the thunk
const data = await dispatch(postSpotifyAlbums(obj));
console.log("result", data);
// we didn't return anything in the error case so it would be undefined
if (data) {
// do something with success
}
};
redux-toolkit includes a helper function createAsyncThunk that automatically creates "pending" "rejected" and "fulfilled" actions in one step. The return value here is the final action that was dispatched.
When dispatched, the thunk will ... return a fulfilled promise containing the final dispatched action (either the
fulfilled
orrejected
action object) - docs
action
const postSpotifyAlbums = createAsyncThunk(
"POST_SPOTIFY_ALBUMS",
async (payload) => {
const args = {
method: "POST",
url: BASEurl,
params: {
token: payload.token,
albumCode: payload.albumCode,
albumGenres: payload.albumGenres,
userCode: payload.userCode
}
};
const spotifyCategories = await axios.request(args);
return spotifyCategories.data;
}
);
component
const doDispatch = async () => {
const action = await dispatch(postSpotifyAlbums(obj));
console.log("result", action);
// we could have the success or the failure action
if ( action.type === postSpotifyAlbums.fulfilled.type) {
// do something with success
const data = action.payload;
} else {
// do something with error
const error = action.error;
}
};