Search code examples
reactjsreact-hooksreact-custom-hooks

How can I re-trigger a custom hook inside my react component, when its states have not changed?


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.


Solution

  • 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;