API call from the root of a React Application.

API call from the root of a React Application.

ยท

3 min read

Hey everyone, hope you all are doing good.

Today I'll be telling something about,

"calling APIs from the root of a React Application."

So, the root of a React Application is...? Yes, you guessed it right!

App.js

TidyShyKookaburra-max-1mb.gif

I was writing an Application in React.js and managing my State Globally with Redux. My Sitemap was Home-Page > Product-Listing-Page > Product-Page. Here problem was, whenever the user refreshes the page, the state of Redux is cleared, and again we need to call an API to fetch data.

UltimateCavernousArmyant-size_restricted.gif

Now, the first solution would be to write code for fetching data, in every Component (Page) where the data is being fetched from Redux.

The code would look like

const fetchedData = useSelector((state)=>state.slice.fetchedData);
//fetching data and subscribing to Redux.

 useEffect(() => {
      //call API only if data is not available.
         if(!fetchedData){
         dispatch(fetchData());
         //calling Custom Action Creator (Thunk)
      }
  }, [dispatch,fetchedData]);

This will call fetchData() method whenever the user refreshes the page. The same code we have to write in all Components (Pages) wherever we are fetching data from Redux.

sleepy-tired.gif

Coming to the point, calling an API from App.js. It seems a bad idea, right? You would argue that the whole App will be re-rendered every time, if the state used in App.js is affected, and you never want that. So how can we call an API from App.js?

confused-1.gif

You can, If you know how React-Router works and how to use that. You can call the API in useEffect Hook of App.js and return all the Routes beneath that.

Something like this

const someData = useSelector((state)=>state.slice.fetchedData);
//piece of State to use in App.js

 useEffect(() => {
    dispatch(fetchData());
  }, [dispatch]);

return (
    <>
      <Switch>
        <Route path="/" exact>
          <Redirect to="/home"></Redirect>
        </Route>
        <Route path="/home/:brand/:id">
          <Product />
        </Route>
        <Route path="/home/:brand">
          <ProductList />
        </Route>
        <Route path="/add-item">
          <AddItem />
        </Route>
        <Route path="/home">
          <Home />
        </Route>
      </Switch>
    </>
  );

What this will do?

As React-Router works, it will only render that Component that is returned for Active-Path. Meaning, that it won't re-render the whole App even if the state used is App.js (here someData) gets affected.

For example, if someData changed and the current route is /home/brand, only ProductList Component will be rendered again.

tenor.gif

Advantages

Now the main advantage here I got was, Even if I refresh any Page from my App, this useEffect of App.js would execute(after mounting the component of-course) and only render the Page on which I currently am (as it would be the active route).

Second advantage would be, you don't need to code for calling an API in every component (as in the first solution), instead, just fetch the data using useSelector as it would also subscribe to the changes in Redux.

photofunky.gif

Caution:

homer-simpson-hammer.gif

This solution may be useful for some scenarios, for others it may cost you performance.

An example where calling an API from App.js won't work could be, when you don't use Switch while using React-Router, then it would render multiple Components.

Another one could be If your App.js contains the Main Component of which the other Components are children Components. If the state used in App.js gets affected then It would result in a re-render of the whole Application and as I said above, will cost you Performace.

P.S.

Optional Chaining (?.anyFunction) was a life-saver here.

Give it a ๐Ÿ‘, if it helped you.

Thank You.

ย