What is the difference between using redux-thunk and calling dispatch() directly - reactjs

I'm in the learning phase of understanding redux state management and still trying to negotiate the bewildering jungle of boilerplate code and middleware, much of which I'm taking on faith as 'good medicine'. So I hope you'll bear with me on this perhaps rudimentary question.
I know that redux-thunk allows action creators to proceed asynchronously and dispatch a regular action at a subsequent time. For example, I can define a thunk action creator in my actions.js:
export function startTracking() {
return (dispatch => {
someAsyncFunction().then(result => dispatch({
type: types.SET_TRACKING,
location: result
}))
})
}
And invoke it from within a React component like so:
onPress={() => this.props.dispatch(actions.startTracking())}
My question is, what advantage does the above code confer over simply dispatching an action from inside an asynchronous callback?
import { store } from '../setupRedux'
...
export function startTracking() {
someAsyncFunction().then(result => {
store.dispatch({
type: types.SET_TRACKING,
location: result
})
})
}
which I would invoke inside my component
onPress={() => actions.startTracking()}
or even
onPress={actions.startTracking}
Is there anything problematic with accessing store directly via an import as I'm doing in the 2nd example?

There is nothing wrong doing so. From the redux-thunk page:
If you’re not sure whether you need it, you probably don’t.
The creator of redux explain the advantage of using it here:
This looks simpler but we don’t recommend this approach. The main reason we dislike it is because it forces store to be a singleton. This makes it very hard to implement server rendering. On the server, you will want each request to have its own store, so that different users get different preloaded data.
Basically, using redux-thunk will save you the store import in each action creator file and you will be able to have multiple store. This approach also give you the opportunity to write a little bit less code and to avoid spaghetti code. Many redux developer don't like to import the store and to manually dispatch because it can create circular dependencies if the code is badly separated (importing an action name from the action creator file in the reducers file and importing the store from the reducers file in the action creator file). Also, dispatching directly an action like that might break the middleware workflow, ie: the action might not be handled by a middleware.
But honestly, if you don't see an advantage to it yet, don't use it. If one day you have trouble with async actions, redux-thunk might be the answer.

Related

Is it mandatory to create action creator in redux layer?

I am new in redux library of react
This is my code
// action creator
export function updateCategories(payload) {
return { type: UPDATE_CATEGORY, payload };
}
// dispatch action creator
dispatch(updateCategories({ list: data }));
But instead if I do like :
dispatch({ type: UPDATE_CATEGORY, payload });
so what is problem if I write action directly in dispatch without returning from function?
Technically it's fine, you can dispatch straight from the component, but there's advantages of having actions creators, e.g.
It creates a intuitively named, reusable function for the dispatch, which you can import as needed, rather than manually dispatching all over the place. So if you want to change how the dispatch of a certain action works, you only have to change in the action creator and not go through all the places it's used and change each one
Simply dispatching something with a payload is fine, but you may also end up having logic to go along with that dispatch, like processing of the payload or fetching of data (using some tool like redux-thunk). It's better to have a single action creator where that's all defined that you can reuse throughout your application, rather than copy pasting that logic all over the place
It helps in code re-usability.
You can go through this link for more Info

What is the difference between Redux Thunk and Redux Saga?

Both Redux Thunk and Redux Saga are middleware of Redux. What is the difference between two and how to determine when to use Redux Thunk or Redux Saga?
Both Redux Thunk and Redux Saga take care of dealing with side effects.
In very simple terms, applied to the most common scenario (async functions, specifically AJAX calls) Thunk allows Promises to deal with them, Saga uses Generators.
Thunk is simple to use and Promises are familiar to many developers, Saga/Generators are more powerful but you will need to learn them.
When Promises are just good enough, so is Thunk, when you deal with more complex cases on a regular basis, Saga gives you better tools.
As an example, what happens when you start an AJAX call in a route/view and then the user moves to a different one? Can you safely let the reducer change the state anyway? Saga makes it trivial to cancel the effect, Thunk requires you to take care of it, with solutions that don't scale as nicely.
In practical terms choosing one or the other one really depends (tautologically) on the project.
One thing to keep in mind is that the two middlewares can coexist, so you can start with Thunks and introduce Sagas when/if you need them (and then choose how/what to refactor with hands on experience... A solution that especially fits "learning projects", MVPs, et similia)
In general terms, Sagas are more powerful and easier to test, but they introduce many new concepts, that can be a bit overwhelming if you're also learning other technologies (Redux especially).
Specifically, while dealing with the simple and effective Redux philosophy (actions (literal objects) fed into reducers (pure functions)), you can deal with side effects with Thunk that is more limited but easy to grasp (Promise.then().error()), or with Saga that requires you to face the (powerful) notion that you can do more complex things with those actions.
It's also worth mentioning (redux-)observable has an even more complex (and even more powerful) paradigm to deal with side effects, just in case you are unfamiliar with it (if you already are, it might be easier to use than learning Saga).
Actually, Both of them are middleware for Redux to deal with asynchronous actions. For knowing the difference between then please pay attention to the following picture:
The middleware box generally refers to software services that glue together separate features in existing software. For Redux, middleware provides a third-party extension point between dispatching an action and handing the action off to the reducer. then reducer makes the new state.
Redux Thunk is a middleware that lets you call action creators that return a function instead of an action object. That function receives the store’s dispatch method, which is then used to dispatch regular synchronous actions inside the body of the function once the asynchronous operations have completed. simple, easy to learn and use with 352B volume
Redux Saga leverages an ES6 feature called Generators, allowing us to write asynchronous code that looks synchronous, and is very easy to test. In the saga, we can test our asynchronous flows easily and our actions stay pure. complicated, hard to learn and understand, 14kB volume but organized complicated asynchronous actions easily and make then very readable and the saga has many useful tools to deal with asynchronous actions
HINT: If you cannot understand the difference between them or understand the redux-saga flow but still you wanna have readable code and avoid callback hell, go after redux-thunk by using async/await, I leave an example for offer:
// simple usage of redux-thunk:
export const asyncApiCall = values => {
return dispatch => {
return axios.get(url)
.then(response =>{
dispatch(successHandle(response));
})
.catch(error => {
dispatch(errorHandle(error));
});
};
};
// async/await usage of redux-thunk:
export const asyncApiCall = values => {
return async dispatch => {
try {
const response = await axios.get(url);
dispatch(successHandle(response));
}
catch(error) {
dispatch(errorHandle(error));
}
};
};

Why use Redux Thunk [closed]

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.

React Redux Thunk with mapDispatchToProps

Looking at examples of how to use mapDispatchToProps most examples follow the following pattern, a function that returns an object with dispatch as an argument:
const mapDispatchToProps = (dispatch) => {
return({
someFunc: (arg) => {dispatch(someFunc(arg))}
})
}
My question is, if all my actions are using thunk, meaning they all have access to dispatch anyway, why would i need to use the above example for mapping functions to props in my containers ?
After experimenting i've figured out another way that seems to work, however im not sure if this is best practice...
Main.jsx
import * as mainActions from '../actions/mainActions'
import * as menuActions from '../actions/menuActions'
const actionsToMap = {...mainActions, ...menuActions}
export default connect(mapStateToProps, actionsToMap)(Main)
Is there anything wrong with this approach?
Both approaches are correct and you can also use bindActionCreators when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass dispatch or the Redux store to it. Technically, that's the only use case for it.
Pulling it from the documentation, mapDispatchToProps can be a function or object.
I think your first approach is good for documentation as one can easily see the signature of the action creators you're using in your component without having to navigate to the action creator file. Other than that, I'm fine using objects(your second approach) in most cases.
Hope this helps!
Separating the concerns is a good idea and in almost all apps it would be a good idea to use Action Creators (which is what you're doing in the second example) as oppose to use plain objects (as in the first).
There are several benefits:
Easier to extend and convert if it isn't buried in an object / function
Easier to test an isolated, functional action. (Have you tried testing the first example?)
Possible to re-use - what happens if some other part of your app needs to dispatch the same action, would you cut and paste this dispatch?
Now consider 1 and 3 together, if you'd dispatched this in several places and you need to extend?
It's not just me saying this, the Redux docs covers it here: https://redux.js.org/recipes/reducingboilerplate#action-creators
That being said, they do also say that plain objects might be enough, but considering how simple action creators actually are it's probably worth making your work extensible in almost all cases.

How to dispatch multiple actions one after another

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 :-)

Resources