0

I am learning react-redux. I got the following problem:

  1. I make two async api calls (with redux-thunk):
  • the first one to fetch country names (in one object, ex: {countries: [{...}, ...]}.
  1. Those country names I use afterwards to make a second api call, to get all the soccer leagues, that are in those countrys (sometimes, there are none, so I get a null). In this case, the call is made with each countryName separatly. I make out of the results an array.
  2. This arrays length is 255m out of which I filter out the null values and map the leagues names.
  3. After I click on a League's name, a page is rendered ({Link} from "react-router-dom";). NOW my problem occurs
  4. When I click, to get back to my home page (<Link to={"/"} >), both useEffect() are making an api call again. Why?

Here is the code for my useEffect():

const dispatch = useDispatch();
const selectAllCountries = useSelector(state => state.allCountries);
const selectAllLeagues = useSelector(state => state.allLeagues);

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

useEffect(() => {
    if(!_.isEmpty(selectAllCountries.data)) {
        selectAllCountries.data.countries.map(el => dispatch(allLeagues(el.name_en)));
    }
}, [dispatch, selectAllCountries.data]);

I tried to make a custom hook and put the useEffect() in there:

const useCountries = getCountries => {useEffect(() => {
dispatch(getCountries());
},[getCountries])}

useCountries(allCountries);

as suggested here: React hooks: dispatch action from useEffect

But it didnt help.

Will be greatful for any help.


ANSWER:

in "./actions/.../allLeagues.js

...
import _ from "lodash";

export const allLeagues = (country) => async (dispatch, getState) => {

    if (!_.isEmpty(getState().allLeagues) && !_.isEmpty(getState().allLeagues.data)) {
        return Promise.resolve();
    } else {
        try {

          ...
        
        }
    }    
}

Question, that was also helpfull: Fetching data from store if exists or call API otherwise in React (take look at answer about getStore())

  • 1
    the component is being unmounted and mounted again when you change routes, so is the expected behaviour – diedu Oct 06 '20 at 20:38
  • This would explain a lot. Thanks. Is there a way to ommit it? I can think of putting the `useEffect`'s in another container. – Dariusz Legizynski Oct 06 '20 at 20:41
  • 1
    that will work, if it is moved to a higher level in the tree to avoid dispatching every time you enter that route, or implement some kind of caching – diedu Oct 06 '20 at 21:18
  • Now, when I know, for what to search for, I found a similar question: https://stackoverflow.com/questions/53113449/fetching-data-from-store-if-exists-or-call-api-otherwise-in-react – Dariusz Legizynski Oct 07 '20 at 05:16

1 Answers1

2

As mentioned in a comment above, the homepage unmounts when you click to go to a new page. When you go back, the page re-mounts and the effect runs again, triggering another API call. You can prevent the API call by checking whether or not the values already exist in your store. I personally like to do this in the action creator, but you could do it in the effect as well.

Checking state in the action creator:

function allLeagues(countryName) {
  return (dispatch, getState) => {
    // Call `getState` and check whether `allLeagues` has been populated yet.
    const { allLeagues } = getState();

    if (allLeagues && allLeagues.data && allLeagues.data.length) {
      // You already have the data, no need to make the API call.
      return Promise.resolve();
    }

    // No data, make the API call...
  };
}

Checking state in the effect:

useEffect(() => {
  // Check whether the league data is set or not.
  if(!_.isEmpty(selectAllCountries.data) && _.isEmpty(selectAllLeagues.data)) {
    selectAllCountries.data.countries.map(el => dispatch(allLeagues(el.name_en)));
  }
}, [dispatch, selectAllCountries.data, selectAllLeagues.data]);

ericgio
  • 3,094
  • 4
  • 25
  • 44
  • 1
    Thats it. I chose the action variant (will post my answer in the end of my question). Now, that I know about `getStore()` it makes things easier. Thank you! – Dariusz Legizynski Oct 07 '20 at 05:11