0

I have a custom hook for fetching data from the server. It takes 3 parameters, which are pageNumber, pageSize, and keyword. I understand if I set one or more of these parameters, the hook gets re-triggered with the new state. But In my component, there is a place when I create data, so once it is created it has to fetch the data again. But none of its parameters, like pageNumber, pageSize and keyword has been updated. I just need it to run once again, to fetch the new data. How do I do this, without changing my states? (in the code below, 'Adapter' is an Axios intance)

This is the hook:

const useFetchLists = (
  url = '',
  currentPage = 1,
  selectedPageSize = 10,
  keyword = ''
) => {
  const [items, setItems] = useState([]);
  const [loading, setloading] = useState(false);
  const [totalPage, setTotalPage] = useState(1);
  const [totalItemCount, setTotalItemCount] = useState(0);

  useEffect(() => {
    const fetchListData = async () => {
      try {
        setloading(true);
        await Adapter.get(
          `${url}?pageNumber=${currentPage}&pageSize=${selectedPageSize}&keyword=${keyword}`,
          {}
        ).then((response) => {
          setItems(response.data.items);
          setTotalPage(response.data.totalPages);
          setTotalItemCount(response.data.totalItems);
        });
      } catch (err) {
      } finally {
        setloading(false);
      }
    };
    fetchListData();
  }, [url, currentPage, selectedPageSize, keyword]);

  return [items, loading, totalPage, totalItemCount];
};

export default useFetchLists;

and this is how I used it in my component, on the initial load of the page.

 const [currentPage, setCurrentPage] = useState(1);
  const [selectedPageSize, setSelectedPageSize] = useState(10);
  const [keyword, setKeyword] = useState('');
  const [items, loading, totalPage, totalItemCount] = useFetchLists(
    ADD_BRAND_URL,
    currentPage,
    selectedPageSize,
    keyword
  );

I want to be able to re-trigger the hook, without setting any of its states because they have not changed, but the data has changed so it has to fetch again.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Sadaf Fara
  • 123
  • 2
  • 10
  • couldn't you just add it to your useEffect dependencies array ? – JimClayton Feb 20 '22 at 06:53
  • add what to the dependency array? nothing has changed, there is nothing to add. I just want the hook to run itself again. No new states – Sadaf Fara Feb 20 '22 at 07:18
  • Yes and the only way to do that would be to add the items variable to the dependency array that would cause a re render when you get new contents in the variable – JimClayton Feb 20 '22 at 08:07
  • but what would that extra dependency be? I could set a variable and increment it everytime I want the hook to re-trigger, but I am pretty sure that is not a clean and correct way to do it – Sadaf Fara Feb 20 '22 at 08:19
  • Use react-query which does the job very good – karianpour Feb 21 '22 at 18:18

1 Answers1

4

I think you can introduce a refetch function, something like this:

const useFetchLists = (
  url = "",
  currentPage = 1,
  selectedPageSize = 10,
  keyword = ""
) => {
  const [items, setItems] = useState([]);
  const [loading, setloading] = useState(false);
  const [totalPage, setTotalPage] = useState(1);
  const [totalItemCount, setTotalItemCount] = useState(0);

  const fetchListData = useCallback(async () => {
    try {
      setloading(true);
      await Adapter.get(
        `${url}?pageNumber=${currentPage}&pageSize=${selectedPageSize}&keyword=${keyword}`,
        {}
      ).then((response) => {
        setItems(response.data.items);
        setTotalPage(response.data.totalPages);
        setTotalItemCount(response.data.totalItems);
      });
    } catch (err) {
    } finally {
      setloading(false);
    }
  }, [url, currentPage, selectedPageSize, keyword]);

  useEffect(() => {
    fetchListData();
  }, [fetchListData]);

  return {
    data: [items, loading, totalPage, totalItemCount],
    refetch: fetchListData
  };
};

export default useFetchLists;
  • I actually did this, but it only works if reFetch is called on let's say an onClick event. It doesn't work if it is called inside another function. I can't figure out why – Sadaf Fara Feb 20 '22 at 08:49
  • @SadafFara Then it's safe to assume there's something wrong on your side. The question doesn't show "another" function. – Estus Flask Feb 20 '22 at 08:56
  • @SadafFara I don't think I can help without seeing the code, can you provide codesandbox link with an example of the problem? – Abdollah Keshtkar Feb 20 '22 at 08:57
  • turns out it was a mistake on my side. this reFetch idea did work. thanks – Sadaf Fara Feb 20 '22 at 09:19
  • Another point to make it better, it’s better to export object instead of array for data. In this case you don’t need to destruct the array in order. You can just get values by it’s key. ```data: { items, loading, totalPage, totalItemCount }``` – Matin Zadeh Dolatabad Feb 20 '22 at 11:42