DEV Community

Fetching data from an api using React/Redux

Markus Claus on March 05, 2019

Starting simple This is my first post here. I decided to share some of the knowledge I earned through making every mistake you can possi...
Collapse
 
jimmymorris profile image
Jimmy Morris

This was a great article, I really appreciate the practical example, too many times it's not so.

One bit of feedback, I noticed in your fetchProducts.js file you have a typo:

dispatch(fetchProductsSuccess(res.products);

you're missing a closing parenthesis at the end of the dispatch

dispatch(fetchProductsSuccess(res.products));

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
markusclaus profile image
Markus Claus • Edited

Thank you very much for the comment Calum. :)

I did it a long time like you described and the solution was great. Then componentWillRecieveProps was marked as UNSAFE_componentWillReceiveProps in React 16.3. It will become deprecated in React 17 and the new getDerivedStateFromProps is here.

So I was wondering how I would solve this without depending to much on changes within the React lifecycle methodes and came up with my solution for the problem.

Putting the code into a function that sounded like a lifecycle method was my approach to keep the code readable and make everyone understand what is happening even if the code gets complicated. I keept it that way. :D

Also, I never got the idea why you would put state from redux into the react state if there is no reason to. I mean, you copy data from one state to another without doing anything with it. Seems like a waste of time. Can you enlighten me? Is there any benefit?

Collapse
 
shabbir profile image
Shabbir Haider • Edited

Even better :

let { requestPending } = this.state;

{ requestPending && <LoadingSpinner /> }
Collapse
 
jignesh1805 profile image
Jignesh1805

componentWillReceiveProps did'nt call.

Collapse
 
gabrielecimato profile image
Gabriele Cimato

Hey Markus! Congrats on your first blog post! Shameless plug, I built a middleware a while ago to help reduce boilerplate especially with async actions like the ones you mentioned in this article, you should check it out!

github.com/Gabri3l/redux-slim-async

Collapse
 
markusclaus profile image
Markus Claus

Hey Gabriele,

thanks for the tip. I know middlewares like yours. I used another one in a project recently. Was a real timesaver.

I will checkout yours for sure.

Collapse
 
gabrielecimato profile image
Gabriele Cimato

Any you would recommend to others out there ?

Thread Thread
 
markusclaus profile image
Markus Claus

Recommend? Not really. I used redux-promise and redux-action to achieve something like your middleware does.

In small applications it was great (as I think your middleware will be) but in larger scale applications there were cases where the thunks got complicated and I had to get rid of all the middlewares I found and do it from scratch (or with my own middleware in that case)

Thread Thread
 
gabrielecimato profile image
Gabriele Cimato

That's interesting! I used this for a medium/large codebase and we were fine so if you have a minute to bring up a complicated Case that made those middlewares unhelpful that would be great! I'm curious to see if there's a way I can adapt this one too not intricate use cases.

Thread Thread
 
shaka60hp profile image
Pablo San Juan

Hi Gabriele, I'm learning about your middleware here,
Do you use it INSTEAD of thunk?

Collapse
 
alegpereira profile image
Alejandro Pereira

Nice post. One question. You do this:

import fetchProductsAction from 'fetchProducts';

but i don't see fetchProductsAction in fetchProducts.js. I see only fetchProducts. Is this a typo or some code is missing?. I believe is only a mistake but just want to confirm.

Thanks.

Collapse
 
markusclaus profile image
Markus Claus • Edited

Thank you for the reply Alejandro.

You can import default exports with whatever name you want. I wanted to use fetchProducts in my code so I can't import it with this name because it would collide with the variable I use in a deeper scope.

To fix this I import everything that is a action with xxxAction and then use it without the Action suffix.

I hope this clarifies things.

Collapse
 
alegpereira profile image
Alejandro Pereira • Edited

You're right. I got confused. I'm learning react so i'm kind of new in those details and scanning the code properly.

Thanks!

Thread Thread
 
markusclaus profile image
Markus Claus

You are welcome mate. Good luck learning :)

Collapse
 
michaelcodes profile image
Michael Cowan

Hi, new to react so excuse my ignorance.
But why would you want to or need to save the api results in state for products?
Wouldn't it be better to just store them in a products list component or something similar? I'm not fully understanding why we would use redux for something like this.

Thanks for the help in advance!!! :D

Collapse
 
patmoore profile image
Patrick Moore

@michael -- because you want the product list to be a shared state.

For example, the product list is useful in a listing component - but it also might be useful in a checkout component that is validating that the product is still available.

Collapse
 
michaelcodes profile image
Michael Cowan

Okay thanks. I'm just trying to understand what you guys take into consideration doing things this way.

I've never worked with any form of state management before trying out react. So the differences are confusing to me compared to my previous vanilla js frontends.

Collapse
 
markusclaus profile image
Markus Claus

My article is more like an example how fetching data from an API works rather then a suggestion to do it like this in this exact case.

Deciding whether or not to put data in a store to share between components is totally up to your special usecase. Sometimes it makes sense, sometimes it doesn't.

For example, I work on a pretty big project right now and I decided to totally get rid of Redux. I only use the React Context API in the rare cases where I need to store data which is shared between components. For example in form handling.

Collapse
 
michaelcodes profile image
Michael Cowan

I see! I'm always open to suggestions and best practices though and you seem to know you're stuff.

Just wanted to understand the thought process.
I'll look up this context api next. Thanks!

Collapse
 
belyazidi56 profile image
Youssef Belyazidi

Hello Mr Markus Claus ,
Thank you for this great tutorial , I really appreciate, i see that you have a little error is : action.payload and you need to change it to : action.products

Thank you!

Collapse
 
rahko profile image
Rahim

Can anybody help me regarding this ?
See I have a redux store which is storing my state on home of home components
Then when I click on some link then it is again storing it into redux thats fine
But when I go back to home page
It should reuse the data from redux store
It should not call rest API again to fetch the data for homepage
It should use it from redux itself

I have used Java for rest API
Middleware thunk for async post

Collapse
 
capscode profile image
capscode

Thanks for this wonderful article.

i have 1 doubt, can someone please explain...

i understand that we have to use redux-thunk or saga to make async calls when we are making api calls inside the store and making an api call by dispatching an action.

but my question is..

  1. do we really need to make api calls by dispatching and action. Cant we simply call the fetchProducts function from component and pass the dispatch to it as argument.

inside the reducer, if we have code like below what's the issue/disadvantages?

function fetchProducts(dispatch) {
        dispatch(fetchProductsPending());
        fetch('https://exampleapi.com/products')
        .then(res => res.json())
        .then(res => {
            if(res.error) {
                throw(res.error);
            }
            dispatch(fetchProductsSuccess(res.products);
            return res.products;
        })
        .catch(error => {
            dispatch(fetchProductsError(error));
        })
    }
Enter fullscreen mode Exit fullscreen mode
  1. can we call api in useEffect or from component like below and update the store's state at 3 different stages of api call like below. Please tell me the disadvantage or issue with this approach.
        dispatch(fetchProductsPending());
        fetch('https://exampleapi.com/products')
        .then(res => res.json())
        .then(res => {
            if(res.error) {
                throw(res.error);
            }
            dispatch(fetchProductsSuccess(res.products);
            return res.products;
        })
        .catch(error => {
            dispatch(fetchProductsError(error));
        })
Enter fullscreen mode Exit fullscreen mode

Thanks a lot in advacne

Collapse
 
nguyenquangtin profile image
Tony Tin Nguyen

Hey Markus, thanks a lot for your guide. Great post!

Collapse
 
dera_johnson profile image
Johnson Chidera

Hi Marcus. I am trying to make an authentication using Google oauth with react, redux, redux-thunk and mongodb but my payload res.data is giving me an empty string even when I am logged in my mongo database. I have been stuck for days.

Collapse
 
tiruvengadam85 profile image
Tiruvengadam85

I have a component, I am passing brand values to the component as props, based on props value, components call different fecth API method in action fecthOMOrder, fecthSVOrder respectively. I need to specify same condition in connect, below condition is not working, please advise, thanks in advance.

if (this.props.brand=="OM")
{
export default connect(mapStateToProps,{fecthOMOrder})(OrderList);

}
else
{
export default connect(mapStateToProps,{fecthSVOrder })(OrderList);

}

Collapse
 
kaushalgautam profile image
Kaushal Gautam

Hi Markus!
Brilliant and insightful article. I will definitely refine my approach based on this. I have a query for you. Say, you have a form that takes a lot of fields as input. It also has some select dropdown fields as inputs which are interdependent. Eg: you select a country from a dropdown and then another dropdown is dynamically filled with the states of the selected country. These data will be fetched from firestore. How would you go about using redux firestore for storing these details and how would you design the actions/middleware functions?

Collapse
 
apekearo profile image
Anthony Pekearo • Edited

Hello Markus, I'm getting fetchProducts() is not a function in your componentWillMount function. And I don't see where it is defined. ComponentWillMount is being depricated, but don't think that is why i'm getting this error. Thank you
componentWillMount() {
const {fetchProducts} = this.props;
fetchProducts();
}

Collapse
 
mukhtorov profile image
Sardor

yeah, it is giving error

Collapse
 
nanettecodes profile image
Nanette

Does anyone have any advice on something.... Im working on an app that is going to make an API call using this technique. It will return a an array of items. each item will have a URL property. When the user clicks on said item (will be displayed in cards) I need a second API call to happen to that url that came from the first call... I cant figure out how to pass that data to the api call. any advice?

Collapse
 
abhi4pr profile image
abhi4pr

you didn't provide ProductList, i am trying

    {products.map(product => (
  • {product.name}
  • ))}

I am getting -> Cannot read property 'map' of undefined

Collapse
 
javaguirre profile image
Javier Aguirre

Thank you for the article Markus!

redux-thunk is a great library, but not easy to test unfortunately, that’s why we decided to go with redux-saga, IMHO makes the code easier to maintain and the learning curve is not much difficult than thunk if you go to the great official documentation. Have you tried it?

Kudos!

Collapse
 
pragin profile image
Pragin Fernando

Hi Markus,

Thanks for the wonderful explanation.

Could you please explain why do we have to import the constants from ../actions.js in reducer.js?

import {FETCH_PRODUCTS_PENDING, FETCH_PRODUCTS_SUCCESS, FETCH_PRODUCTS_ERROR} from './actions';

Collapse
 
vinodku19879019 profile image
vinod kumar

its very good thanks Markus Claus

Collapse
 
alexnikolaiev94 profile image
AlexNikolaiev94

Thank you for this amazing article! It really helps to understand the core premises of Redux. I still keep failing at a certain spot, though. In my component where I try to call the data I get from fetching action, it keeps failing as my render function tries to render the component I need this data first, and only after that the fetch promise finally resolves and shoots the fetchSuccess action. I could give a link to my github if only you could give me even a slightest hint what I've done wrong :D Have a nice day!

Collapse
 
laynier profile image
laynier

Hey, just trying to learn react and redux and your post helped a lot Claus. Just got some lost at view component. If I have a function component how do I use the fetcher action? How do I put the array of products un the props? Thanks for funny and clear descriptions you made. And for your time.
Best,
Laynier

Collapse
 
gonjavi profile image
Javier

HI Markus,

I really appreciate it, I just understood most of the article, it is about to continue learning and practicing, it helped me.
I have a question on the productview component you, shouldcomponentrender, why do you use** const {pending} = this.props;** I noticed and I think it is not being used.

Thanks very much

Collapse
 
szulfiqar profile image
Saad Zulfiqar

Hi Markus,

Let's assume i want to use some value from store and pass it as a parameter to products API call in fetchProducts.js. How can i access that ?? Something like

fetch(https://exampleapi.com/products/${store.someVariable})

how can i access store object in fetchProducts.js ??

Collapse
 
mrhassantariq profile image
Hassan Tariq

There a few methods that can help you using state variable in thunk function:

  1. You can export the state. Create a separate .js file and export the state object by using createStore(reducerName) method, then import that state object and use the getState() method to access the store.

  2. You can directly use getState in your app-thunk function by simply passing it as an argument like return (dispatch,getState) => {} and then use this getState() method to access the store.

There are some other methods but these should work.

Collapse
 
dcsan profile image
dc

your action.js is missing commas

function fetchProductsSuccess(products) {
    return {
        type: FETCH_PRODUCTS_SUCCESS , // << missing
        products: products
    }
}
Collapse
 
sebastienlorber profile image
Sebastien Lorber

This code is subject to race conditions.

Check my post about that subject here: dev.to/sebastienlorber/handling-ap...

Collapse
 
feroz101 profile image
feroz101

Hi Markus, Nice tutorial can you please share the code.

Collapse
 
jhoanborges profile image
Jhoan Borges

I was stucked with this but thanks to your it's solved. This is the ebst guide ever, even being short.

Collapse
 
mwangikibui profile image
mwangiKibui

Thanks this really helped me in my app

Collapse
 
lucilag profile image
Lucila Gaudio

Hi Markus! Is a really good post!
I hope it's not much to ask, but would you know how to do it with react hooks and redux? I can't understand how to initialize a state before it is rendered without using componentWillMount.

Collapse
 
erkaner profile image
erkaner

Hello! Is it possible to use a function component instead of a class component for ProductView ? How would the code change with useEffect hook? Thanks!

Collapse
 
markusclaus profile image
Markus Claus

I actually wrote an article about React Hooks not long ago and there is an example for a fetch hook. Check it out

Collapse
 
ankitsoni301188 profile image
ankitsoni301188

hi, can u please help me little confuse
whenever i am calling my action funtion on componentdimount
it throws an error function not deefined?

Collapse
 
j0nimost profile image
John Nyingi • Edited

Is there a book or video describing the use of these react design patterns and/or the use of redux? For beginners maybe?

Collapse
 
markusclaus profile image
Markus Claus • Edited

There are literally thousands out there. I can recommend Frontend Masters, they got plenty on all the relevant subjects but they are not free. Also YouTube is full of content. Udemy has some pretty good courses for little money, too.

Collapse
 
simphiwehlabisa profile image
simphiwe sifiso hlabisa

Hey markus wheres the link for a repo man 🤥

Collapse
 
gilangaramadan profile image
Gilang A. Ramadan

Thank you! it help me to understand how to implement redux in a simple way :)

Collapse
 
shmidtalex profile image
Alexander

Hi, Markus! I've got a message like: undefined is not an object (evaluating 'action.type'). How do you think, what may be a reason, that action is undefined in reducer.js?

Collapse
 
inezabonte profile image
Ineza Bonté Grévy

Would be great if you created a repo for this

Collapse
 
chadsteele profile image
Chad Steele

I'd love it if you wanted to dissect my Redux one line replacement hook... useSync
dev.to/chadsteele/redux-one-liner-...

Collapse
 
markolazic profile image
Marko Lazić

Kul. Will try.

Collapse
 
muhammadnauman profile image
Muhammad Nauman

The best article to have a better understanding of redux and usage of APIs with redux. Thanks a bunch.

Collapse
 
iamashusahoo profile image
Ashutosh

Hi Markus,

Thanks for the beautiful article... It clarified a lot of things working with Redux

Collapse
 
amdsubham profile image
Subham Routray

Very much helpful, Thanks, keep posting such amazing concepts

Collapse
 
borispoehland profile image
Boris Pöhland

Why are you still returning res.products in fetchProducts.js? Can't this be omitted? Thanks in advance!