How can I know when a redux-saga function has completed in the calling code - redux

React, redux, redux-saga
I dispatch an action, say CREATE_REQUESTED to the store.
Redux-saga runs, and makes the async call to the server.
After the saga completes, i.e. blocks for the next CREATE_REQUESTED I want to execute additional code, from the container/component from which the first CREATE_REQUESTED was initiated.
// pseudo code
class Cmp extends React.component {
onCreateClick(id) {
const record = {id, name: 'alabala'}
// I am missing the .then() part
this.props.dispatch({type: 'CREATE_REQUESTED', record}).then(created => {
console.log(created)
}
}
}
Is there a way to do that? How?
If not, how am I supposed to design this task?

One approach could be to pass (resolve, reject) options along with the action, and make the saga call them on succcess/failure. Seems OK.
https://github.com/yelouafi/redux-saga/issues/161

Related

How to have a Subject as a payload in an immutable Ngrx action?

Use case: dispatch an action with a cold observable in the payload.
When an effect catches the action, it subscribes (through mergeMap, switchMap, whatever...) to this observable and send back another action. Classic Ngrx process.
export class ServicesStore {
dispatchObservable(operation$: Observable<unknown>) {
this.store.dispatch(serviceRequestAction({ operation$ }));
}
}
export class ServicesEffects {
serviceRequest$ = createEffect(() =>
this.actions$.pipe(
ofType(serviceRequestAction),
mergeMap((action: ServiceRequestAction) => {
return action.operation$.pipe(
map((result) => {
// send back an action with the result
})
);
})
)
);
}
Usage:
this.servicesStore.dispatch(this.userService.getAll$());
It works well.
But if this observable is a Subject (say MatDialog.open().afterClosed()) it will break the immutable action Ngrx rule.
Because of the inner subscription, the Subject adds an observer into its internal structure, thus breaking the action immutability. It then triggers the Ngrx runtime checks.
Of course I can disable these check, but I am looking for a better away around this. For example, is there a way to clone a Subject ?
Or any other way to allow a Subject into the action payload ?
AFAIK adding a subject to a NgRx Action isn't supported (if you want to keep the runtime checks enabled).
The classic NgRx process is that the effect results in a new action (popular ones are success and failure).

is it possible to keep redux dispatch function in class performing async actions?

I am beginner in Redux and I want to use it for asynchronous logic. Redux style quide recommends to use redux-thunk for it, but it seems I don't need it if I use redux in following way:
class Actions {
constructor(dispatch) {
this.dispatch = dispatch;
}
someSyncAction1(data) {
this.dispatch({
type: SOME_SYNC_ACTION1,
payload: data,
})
}
someSyncAction2(data) {
this.dispatch({
type: SOME_SYNC_ACTION2,
payload: data,
})
}
async someAsyncAction(data1, data2) {
this.someSyncAction1(data1);
await somethingAsync();
this.someSyncAction2(data2);
}
}
// then in my react component:
function MyComponent() {
const dispatch = useDispatch();
const actions = new Actions(dispatch);
//...
return <div onClick={() => actions.someAsyncAction(1, 2)}></div>;
}
It seems to be a simple way but I worry whether it can lead to errors. Please help me to understand what is wrong with it.
This is not very different from the useActions hook referred to in the Hooks documentation - at least for the synchronous stuff.
In the async stuff, you are losing functionality though: Thunks can at any given time access the current state by calling getState.
Also, and this is probably more important: thunks are not only recommended, they are a pattern almost every redux developer knows. So they look at your code and can immediately go to work. Your pattern on the other hand is not established, so it will lead to conflicts if someone other will ever take over your code - without any real benefit.

What's the point of using Redux-Thunk vs normal async code? [Examples Included]

I've always struggled to get my head around Redux-thunk, as it really don't understand what great purpose it serves. For example, here's a random Redux-Thunk example I found from a website:
export const addTodo = ({ title, userId }) => {
return dispatch => {
dispatch(addTodoStarted());
axios
.post(ENDPOINT, {
title,
userId,
completed: false
})
.then(res => {
setTimeout(() => {
dispatch(addTodoSuccess(res.data));
}, 2500);
})
.catch(err => {
dispatch(addTodoFailure(err.message));
});
};
};
It's seemingly simple, addTodo is a function that takes in the title and userId and returns a function with dispatch as a parameter, which then uses dispatch once and then again for the response of the HTTP request. Because in this case Redux-Thunk is being used, you would just do dispatch(addTodo(x,x));
Why would I not just do something like this though?
function addTodo(dispatch, title,userId){
dispatch(addTodoStarted());
axios
.post(ENDPOINT, {
title,
userId,
completed: false
})
.then(res => {
setTimeout(() => {
dispatch(addTodoSuccess(res.data));
}, 2500);
})
.catch(err => {
dispatch(addTodoFailure(err.message));
});
}
Then from anywhere, I can just call addTodo(dispatch, x, x);
Why would I use the Redux-Thunk example over my own?
Here are few points through which i will try to explain why should go with redux-thunk.
Its middle ware so it will make dispatch and state object available in every action you define without touching you component code.
When you pass dispatch function which is either from props or from mapDispatchToProps(react-redux) which creates closure. This closure keeps memory consumed till asyc operation finished.
When ever you want to dispatch any action, after completing or in async operation you need to pass dispatch function and in this case you need to modify two files like your component and actions.
If something is already available and tested with lot effort and community support why not use it.
your code will be more readable and modular.
Worst case for both approach, say after completing project, need to change thunk approach, you can easily mock thunk middle ware with your custom middle ware code and resolve it but in case of passing dispatch function it will refactoring all code and search and replace and find way to manage it.

Does applying Redux-Thunk midleware to redux change all actions to be executed asynchronously?

I have a project in which I have applied the redux-thunk middleware to my redux store. Now I have several thunks in my code and this are also being dispatched, but they return ThunkAction<Promise<void>, void, void, AnyAction> so I assume these are async.
In other places of my code I’m directly calling the dispatch method on the store. Does this actions also become asynchronous as an effect of applying middleware or do they remain synchronous?
For example If i do:
store.dispatch(someAction);
Would that still be synchronous?
Thanks in advance.
Yes.
Dispatching is 100% synchronous by default.
If you add middleware, a middleware may alter, delay, or stop an action from progressing through the dispatch pipeline.
However, in this case, the redux-thunk middleware does not do anything asynchronous. It simply checks to see if the "action" is actually a function, and if so, executes it immediately:
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => (next) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
If the thunk middleware is applied, store.dispatch(someThunkFunction) will return whatever the thunk function returns. So, if you return a promise from the thunk, that promise will be returned from store.dispatch().
For the TS types, the first generic argument should indicate the expected return type of the thunk function. However, you would likely actually have to specify that yourself - it shouldn't be appearing randomly.

mix redux-thunk with redux-observable

I have an app using redux-thunk and want to try out redux-observable.
Currently I have a thunk action creator that does the following:
const initState = () => {
return dispatch => new Promise((resolve,reject)=>{
//these each return axios promises as they get data from the server
const pr1 = dispatch(processData1())
const pr2 = dispatch(processData2())
Promise.all([pr1,pr2])
.then(r=>resolve(true))
.catch(e=>reject(e))
})
}
}
and this is called from my component in componentDidMount like so:
this.props.initState()
.then(r=>this.setState({loaded:true}))
.catch(e=>this.setState({loadError:true}))
Now I want to try redux-observable Can I combine it with redux-thunk and replace the processData2() call to instead dispatch an action which is dealt with by redux-observable?
i.e.
const pr2 = dispatch({type:OBSERVABLE_PROCESSDATA2})
Now as far as I can tell, this isn't going to return a promise so the original code will now break as in Promise.all will .then(r=>resolve(true)) immediately even though redux-observable epic has not yet processed it.
So is there a way I can wait for that dispatch to do the async stuff in the epic or do I need to basically go redux-observable all the way in this case?
You can combine redux-thunk and redux-observable in the same project.
actions ---> redux-thunk ---> redux-observable ---> store
But the idea of redux-observable is action$ in and action$ out. So you will need to write all your async logic in epics, and don't have access to the returned observable which is action stream.
So it's either you may want to convert the whole initState to an epic or just use rx.js directly in this thunk without creating epics

Resources