skip to Main Content

I am using react-query hook for data fetching. I have some filters (Playground). I want to call the api only when the applied filters are valid. I am using enabled property to conditionally fetch. But my concern is, I have passed a function to enabled property which would be executed on every re-render. So, if I click on Re-render button, even though my filters was not changed, but the isFiltersValid function is called. In this example isFiltersValid is not a heavy computation, but what if it was a heavy computation function.

In case, if I just use useEffect, my code would look like:

  useEffect(()=>{
    //  here `isFiltersValid` is called only when filters change and not on every re-render
    if(isFiltersValid(filters)){
       queryFn()
    }
  },[filters])

How can I stop executing the isFiltersValid when filters are not changed. I can either memoize the result of isFiltersValid or can have a state which tells whether the status is valid or not and then I can pass that value to enabled. But is there any other approach without useMemo or using a state?

2

Answers


  1. You can handle this by creating a custom hook to manage the filter validation. This way, the isFiltersValid function will only be called when the filters change, and it won’t be triggered on every re-render. Here’s an example:

    import { useState, useEffect, useCallback } from 'react';
    import { useQuery } from 'react-query';
    
    // Custom hook to validate filters
    const useFilterValidation = (filters, isFiltersValid) => {
      const [areFiltersValid, setAreFiltersValid] = useState(false);
    
      const validateFilters = useCallback(() => {
        setAreFiltersValid(isFiltersValid(filters));
      }, [filters, isFiltersValid]);
    
      useEffect(() => {
        validateFilters();
      }, [filters, validateFilters]);
    
      return areFiltersValid;
    };
    
    const MyComponent = ({ filters }) => {
      const areFiltersValid = useFilterValidation(filters, isFiltersValid);
    
      const { data, error } = useQuery('fetchData', queryFn, {
        enabled: areFiltersValid,
      });
    
      return (
        <div>
          <button onClick={() => console.log('Re-render')}>Re-render</button>
          {/* Render your data or error */}
        </div>
      );
    };
    Login or Signup to reply.
  2. it is ok to recalculate the isFiltersValid on every rerender. And when and only when the computation became expansive you can memoize. It is a bad practice to pre-optimize your code as it can became slower and hard to maintain !
    so you can just put it in the useQuery

    const { data: response } = useQuery({
         queryFn: yourQuery,
         queryKey: yourKey,
         enabled: isFiltersValid(filters)
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search