1

Im using react functional components.

To call data from an api , there are available filters and pagination. When I change a filter type, the pagination has to return to the first page.

const pageChange = (page) => {
        setPage(page);
    };

 useEffect(() => {
        async function fetchData() {
            const dateFilter = start && end ? `start=${start}&end=${end}` : null;
            const pageFilter = `offset=${
        (page - 1) * ITEMS_PER_PAGE
      }&limit=${ITEMS_PER_PAGE}`;
            const defaultFilters = `${dateFilter?dateFilter:''}${dateFilter?'&':''}${pageFilter}`;
            let request = null;
            switch (type) {
                case "upcoming":
                    request = fetchUpcomingLaunches(defaultFilters);
                    break;
                case "successful":
                    request = fetchLaunches(`${defaultFilters}&launch_success=true`);
                    break;
                case "failed":
                    request = fetchLaunches(`${defaultFilters}&launch_success=false`);
                    break;
                default:
                    request = fetchLaunches(defaultFilters);
                    break;
            }
            try {
                setIsLoading(true);
                const response = await request;
                setItems(getItems(response.data));
                setIsLoading(false);
            } catch (err) {
                setIsLoading(false);
            }
        }
        fetchData();
    }, [start, end, type, page]);

Im using material ui pagination :

   <Pagination
          count={20}
          variant="outlined"
          shape="rounded"
          size="large"
          page={page}
          onChange={(event, val) => pageChange(val)}
        />

Here the start, end and type are filters . If any of there filters changes, the api has to be called and the data should be refreshed. The api has to return the paginated response based on the page . My problem is that when any of the other filters are changed , the page should reset to the first page and data should be loaded from the first page. Is it possible to use two useEffect hooks? I have tried useEffect with type, start, end dependecies . As of now the api is getting called two times as setPage is called again.

NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
Mohit Harshan
  • 1,916
  • 1
  • 18
  • 41
  • I had a similar question [here](https://stackoverflow.com/questions/57773502/multiple-useeffect-react-useeffect-has-missing-dependencies) when I was new to react. Check the codesandbox in the answer. – SuleymanSah Mar 06 '21 at 13:57
  • @SuleymanSah viewed it , i dont get how it will prevent useEffct being called twice – Mohit Harshan Mar 06 '21 at 14:07
  • It seems your question is a bit of different from mine. – SuleymanSah Mar 06 '21 at 14:52
  • @SuleymanSah true.Actually this issue will be fixed if we can get the total count of items from backend . the Pagination component will handle it – Mohit Harshan Mar 06 '21 at 15:03
  • 1
    This can solve your problem: https://stackoverflow.com/questions/57240169/skip-first-useeffect-when-there-are-multiple-useeffects – SuleymanSah Mar 06 '21 at 17:09
  • If you can add it as an answer to this based on my question, I think it will help others too @SuleymanShah – Mohit Harshan Mar 06 '21 at 17:17

2 Answers2

1

after filter changed, you can setPage to page 1 and add setPage in useEffect with condition filter. for example

useEffect(() => {
   setPage(1);
},[start, end])
danhuong
  • 202
  • 1
  • 8
  • 1
    I have tried this, in this case the api will call two times in the first Useeffect and data will be affected based on which request will return the response first – Mohit Harshan Mar 06 '21 at 13:36
  • @MohitHarshan I don't think this second useEffect causes the api being called two times. There must be some other reason, if you can provide a basic version of your app in codesandbox, it would be easy to find the reason. – SuleymanSah Mar 06 '21 at 13:54
  • Yes, for example , the dependecy start changes , the api useeffct will be called because it depends on start, , when setPage is called in first useEffect, it will call second useEffect again @SuleymanSah – Mohit Harshan Mar 06 '21 at 13:56
1

You need add a new useEffect with filter dependencies, and take advantage of useRef to prevent the api being called two times when a filter changes.

Idea taken from this answer

const isFilterApplied = useRef(false);

useEffect(() => {
    console.log("Filter change effect")
    isFilterApplied.current = true;
    setCurrentPage(1);
  }, [start, end, type]);
  
  useEffect(() => {
    async function fetchData() {
      const dateFilter = start && end ? `start=${start}&end=${end}` : null;
      const pageFilter = `offset=${(page - 1) * ITEMS_PER_PAGE}&limit=${ITEMS_PER_PAGE}`;
      const defaultFilters = `${dateFilter ? dateFilter : ""}${dateFilter ? "&" : ""}${pageFilter}`;
      let request = null;
      switch (type) {
        case "upcoming":
          request = fetchUpcomingLaunches(defaultFilters);
          break;
        case "successful":
          request = fetchLaunches(`${defaultFilters}&launch_success=true`);
          break;
        case "failed":
          request = fetchLaunches(`${defaultFilters}&launch_success=false`);
          break;
        default:
          request = fetchLaunches(defaultFilters);
          break;
      }
      try {
        setIsLoading(true);
        const response = await request;
        setItems(getItems(response.data));
        setIsLoading(false);
      } catch (err) {
        setIsLoading(false);
      }
    }

    if (isFilterApplied.current && currentPage !== 1) {
      return;
    }

    console.log("Main effect")

    fetchData();
  }, [start, end, type, page]);

  useEffect(() => {
    setPage(1);
  }, [start, end, type]);

  const changePage = (page) => {
    isFilterApplied.current = false;
    setCurrentPage(page);
  };

A sample codesandbox with a different code base if it helps.

SuleymanSah
  • 17,153
  • 5
  • 33
  • 54