I am kind of in dilemma when do we need to use redux actions and redux saga actions.
I don't mean to ask when to use redux and when to use redux-saga. But I would like to know that what scenario do we need to use redux actions when we use redux saga. Or don't I need to use redux actions when using redux saga?
Please help me understanding the use cases of redux when using redux-saga.
Not sure if this is what you meant, but just in case: the actions themselves are indistinguishable between redux and redux-saga. In both cases, an action is an object with a type, and possibly a payload. For example, this is an action:
{
type: 'DO_STUFF',
value: 3,
}
When you dispatch an action, it's first going to go into your middlewares. Redux-saga is an example of a middleware, and it can decide whether it wants to do anything with the action. If the action gets past redux-saga, it then goes to the reducers.
So i believe what you're asking is: when should you handle an action with a saga, and when should you handle it with a reducer. The answer to that comes down to the reason redux-saga and similar middleware were created in the first place:
Reducers are always synchronous pure functions.
So you'll use a saga when you want to do something asynchronous and/or impure. The asynchronous part of that is the thing that comes up most often. If you want to fetch data, it will be in a saga. If you want to set up an interval to do something over time, it will be in a saga.
On rare occasions you might have something that's synchronous, but impure, and that might also be something you put in a saga. One recent example i had was that i wanted to dispatch an action, and rather than updating the application state, i wanted it to save something to local storage. This happens synchronously, but since it's a side effect it's better for me to put it in a saga.
As requested in the comments, a clarification about synchronous but impure. A function is synchronous if it does all its work before it returns. A function is pure if it 1) has no side effects and 2) for a given input, it always returns the same output.
A side effect is when a function changes something external to itself, but by a means other than its return value. With a pure function, i should be able to call it and assume that nothing has changed outside of that function. For example:
localStorage.setItem('data', 'hello world');
doSomething();
console.log(localStorage.getItem('data'));
If i know nothing about doSomething except that it's pure, then i can be certain that localStorage.getItem('data') will return 'hello world'. But on the other hand if doSomething is impure, then i can't make that assumption. In principle, the value in local storage could have been changed, resulting in a different log statement.
So a function that modifies local storage, such as the following, is impure despite being synchronous:
const doSomething = (value) => {
localStorage.setItem('data', value);
}
The second way something could be impure is if it doesn't always return the same thing for its same inputs. For example, the following function is synchronous but impure:
const getTime = () => {
return Date.now();
}
If i call that multiple times, i will usually get different numbers each time.
Related
In my thunk, I have two dispatches in an array called dispatches which modify the Redux store. Only after both of them have completed (i.e., modified the Redux store), I want to dispatch finalDispatchCall. I tried putting them both in a Promise and called then, but I still see the finalDispatchCall being made before the secondDispatchCall has updated the Redux store.
const dispatches = [];
dispatches.push(dispatch(firstDispatchCall());
dispatches.push(dispatch(secondDispatchCall());
Promise.all([...dispatches]).then(() => {
dispatch(finalDispatchCall());
})
.catch(error => {
logger.error(
`Print out error - ${error}`
);
});
Is there a way to make sure a dispatch has completed before calling another dispatch?
EDIT (more details):
The firstDispatchCall is making an API call (returning fetch) and dispatching an action in the then statement to update the redux store. The secondDispatchCall is also making an API call (returning fetch) and dispatching two other actions in their then statements which each make their own API calls and dispatch actions to update the redux store.
I want to wait until all of this is complete before making that finalDispatchCall.
As long as firstDispatchCall() and secondDispatchCall() are sync, then redux guarantees that they'll arrive synchronously, in sequence, and that subsequent calls to dispatch() will act upon the updated state. But, if you want to be absolutely certain, you can use store.subscribe(), to kind of procedurally await all the changes you're expecting, and read the store on each change to confirm they're all there. This will actually be essential if first and second DispatchCall are async.
But, the question is whether you really need to know, from that specific thunk, when all the dispatches have landed. Redux is an event bus, and as such offers many ways to skin the async cat. It might help to understand more about the problem you're trying to solve by waiting for these dispatches in order to dispatch the last one. It may be that you don't really need to do that...
I recommend reading the Redux team's take on this exact question: "Should I dispatch multiple actions in a row from one action creator?". Especially note there:
"In general, ask if these actions are related but independent, or
should actually be represented as one action."
Newcomers to Redux often use multiple actions for what could be a single action, because they forget that multiple reducers can all listen to the same action.
I am using React and Redux (react starter kit).
I have a set of action, and when some are called, I want to dispatch side effects.
For exemple, I have a workspace that contains projects, if workspaceID in the store change, (using my action setWorkspaceId) then, the projects store will notice the change, and start execute some api call to update itself.
IN angular/ngrx, I was using Effects, so the Effect where dispatching other action when a certain action was called.
What is the redux way ? I was checking into Redux-Saga, but is there something else or already built in ?
Left alone, Redux just accumulates state from the actions it receives via dispatch, so there is no single Redux-blessed way to trigger side effects from actions.
But it supports middleware, which allows you to monitor, subscribe to and even change actions that are dispatched.
If you're familiar with RxJS via ngrx, redux-observable might be something worth looking into. It allows you to consume and emit actions via RxJS's observable type. The use case you describe of triggering an API call when a value changes would be well-suited to this.
But as you say, there's also redux-saga, which uses generators to model asynchronous logic around the consumption and production of Redux actions and other side effects. There are pros and cons to these and all the other solutions out there.
Ultimately I suggest starting with what's most familiar to you, especially if you're new to Redux.
One piece of unsolicited advice - middleware is easy to overuse. Be wary of doing in middleware and side effects that which can be achieved in a reducer.
It's easy and tempting enough to set up middleware to dispatch action B in response to action A, but if all action B does is update some state, maybe that state's reducer can just react to action A.
What is the redux way?
Use mapStateToProps to subscribe for store changes.
Then use useEffect in your function component, with workspaceID as dependency, to do some side effects (i.e calling an api).
function Component(props) {
useEffect(
() => {
// call api
}
, [props.workspaceID] // only run effect when workspaceID changes
)
}
mapStateToProps(state) {
return {
workspaceID: state.workspaceID // subscribe to workspaceID changes in store
}
}
connect(mapStateToProps, {})(Component)
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Why use Redux Thunk then one can do something like this:
ReadableAPI.getCategories().then((categories)=>{
console.log('after getCategories', categories)
this.props.dispatch(addCategories(categories))
})
Isn't this more straightforward and achieves the same thing?
This answer from Dan Abramov explains beautifully why you would want to use redux-thunk in your application. One more benefit of using redux-thunk in your application is that you keep your business logic separate from your view part (React in your case). We had a use case where our app was written in backbone and we wanted to re-write our whole app in React. We realised that it is easy if your view and collection/models are separate. We started depreciating just the html templates and not the collections. When we deprecated all the html templates, we started using Redux in our app and deprecated our collections too.
What I want to put here is that we had our view and business logic separate, we could refactor that easily. Similarly, with React and Redux, you would want to keep that different, so that if something new comes and replaces Redux, at least you won't have to deprecate your views and you just will have to change your business logic.
Redux Thunk basically allows us to delay the dispatch of an action, i.e we can handle the action returned by the action creator and call the dispatch function when we really want to dispatch.
Your example is incomplete and it was frustrating to follow how you arrived at that oversimplified solution. After researching it I realized, you probably have some ReadableAPI.js file somewhere you should have posted with what is probably a configuration using fetch and inside of it you probably have something like this:
export const getCategories = () =>
fetch('http://localhost:3001/categories', {headers})
.then(res => res.json())
.then(data => console.log(data))
which ties into your:
ReadableAPI.getCategories().then((categories)=>{
console.log('after getCategories', categories)
this.props.dispatch(addCategories(categories))
})
So in this solution you are returning a Promise which is an object which essentially gives us notification when some amount of work such as a network request is completed and in order to get notified we chain on the .then() function which we pass an arrow function like you did: then((categories)=> and that arrow function will be called at some point in the future.
It looks like you are referring to that data as categories and you are console logging 'after Categories', categories.
What we need to know is what are the different properties attached to that categories object? Does it have a data property? Does it have a results property with some actual data in it? Is there a categories.data.results that contains whatever the data is?
So let's just say the answer is yes to all the questions.
You are going about that in a bit of a hard way in order to deal with asynchronous requests because it's not just that snippet of code: there is also what's inside the ReadableAPI.js file, right? Also, you are using Promises that can get kind of hairy and you would have already put together two files just to deal with asynchronous request which would be okay if it was just a plain Reactjs application, but you mentioned your approach as an alternative to Redux-Thunk which implies using Redux.
For your approach in the vanilla Reactjs space I would use Axios and implement the async/await syntax, but with Redux involved you don't want to use a Promise.
Now, the action creator I had to make up in the ReadableAPI.js file would not work in a Redux environment because it does not return a plain JavaScript action object and so we would have to use a custom middleware as the error says to do.
So how does a middleware like Redux-Thunk work? Redux-Thunk essentially relaxes the rules around an action creator.
The purpose of Redux-Thunk is not to be passed a request object and it will take it away and go to work for you.
Redux-Thunk is an all purpose middleware that allows us to deal with asynchronous action creators, but it also allows us to do many other things as well.
With Redux Thunk involved, your action creator can return an action object. If you return an action object it still must have a type property and if it is an action object that gets returned it can optionally have a payload as well.
The other thing that Redux-Thunk does is allow you to return either an action object or a function.
If you return a function, Redux-Thunk will automatically call that function for you.
That's it, thats all Redux-Thunk does. However, One thing Redux-Thunk does really well is to manually dispatch an action. That is the key part. With Redux-Thunk we can manually dispatch an action at some point in time in the future.
So we get this new action created and it can be a plain JavaScript object or a function, but when we are dispatching it manually inside of Redux-Thunk or inside of a function it's basically always going to be a plain object.
So we will dispatch this action and it will flow back into dispatch and dispatch will send it right back into Redux-Thunk and Redux-Thunk will ask if it's an action or object.
When it's an object, Redux-Thunk forwards it automatically to all the different reducers.
With Redux-Thunk we can return a function and if we do, that function gets invoked with dispatch and getState arguments and with those two functions we have unlimited power over our Redux store and we can change any data and read any data and at any point in time in the future we can manually dispatch an action and update the data inside of our store.
Where am I getting the dispatch and getState? From the Redux-Thunk library source code:
https://github.com/reduxjs/redux-thunk/blob/master/src/index.js
src/index.js:
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
If you look at the if conditional you see the body of the actual logic that is going on. Did you just dispatch an action? If so, is it a function? If it is, then Redux-Thunk is going to invoke that action with dispatch and getState.
If our action is not a function, Redux-Thunk does not care about it, so on it goes to the next middleware as indicated by the return next(action);, otherwise on to the reducers if there is no middleware to run.
I'm in a problem when update store of my react redux app.
How can I make store update thenable?
As you know, all updates of states are async, so we have to use componentDidUpdate method if I do something as a callback function of state update. But these are sometimes complicated. I'd like to make this simple, by something like making them thenable method. Does have any body any idea?
The reducer function supposed to be pure so the async logic should not be there.
There are few middlewares you might be interested in:
redux-thunk allows you to have action creator that returns a function which dispatch and getState from store are injected into a normal action which means can delay the dispatch however you want. But it has limited power. (which you might not need more than that)
redux-saga use generators to explain all the side-effects and async operation in terms of data. It is more powerful than thunk, you can do complicated async interaction, for example, racing between multiple actions. But the downside is there will be more action you need to create and unpredictability caused by action dependencies.
redux-observable is claimed to be more sophisticated than saga. It is based on Rx observable stream and you can manipulate stream of actions with map flatMap filter which similar to array's method but there are more you can use. For me, it's interface looks much nicer than saga. Some might argue against the learning curve needed for understanding Rx.
In my react / redux application I often want to dispatch multiple actions after another.
Given the following example: After a successful login I want to store the user data and after that I want to initiate another async action that loads application configuration from the server.
I know that I can use redux-thunkto build an action creator like this
function loginRequestSuccess(data) {
return function(dispatch) {
dispatch(saveUserData(data.user))
dispatch(loadConfig())
}
}
So my questions are:
When the first dispatchreturns, is the state already changed by all reducers listening for that action? I'm wondering if the two dispatch calls are run strictly sequential.
Is this approach considered best practice for dispatching multiple actions? If not, what would you suggest alternatively?
Thanks for any help!
Yes redux-thunk allows you to do as you say, and yes it is a best practice for dispatching multiple actions (one that I prefer over the alternatives because of it's simplicity). The state is indeed updated as soon as you dispatch (by the time it returns), which is why you are given a function to retrieve the state in a thunk, instead of simply a reference to the state. In that way you can alter the state with one dispatch, and then call getState() to get a reference to the new state to read from if you need to.
redux-thunk is exactly what you are looking for. I consider it very good practice.
To answer your question, indeed when the first dispatch returns the state is already changed by the called reducers.
I know its a late response :-P You can do this by using Redux-Thunk and also checkout Redux-Saga. Redux Saga provides an amazing way to handle loads of actions at the same time. Below is an example of dispatching multiple actions using Redux-Thunk
function getAndLoadSider(moduleName){
return function(dispatch){
return doSomeApiCall(someData).then(function(item){
let _item = someOtherFunction(item.collections);
let _menuData = {
name: item.name,
key: item.key
};
return new Promise(function(res, rej){
dispatch(actionOne(_menuData));
res(_item);
}).then((_item) => dispatch(actionTwo(_item)))
}
}
Above method works well for your case when one action is dependent on the first. This is a promise based approach. If you don't like to do a lots of Promise coding I recommend you go for Sagas. Check out this link https://redux-saga.js.org/docs/advanced/ComposingSagas.html where you will learn how to compose sagas. Learning curve is steep; but once you are done, Sagas will make you a ninja redux dev.
Hope this helps :-)