skip to Main Content

Considering such code below:

const [list, setList] = useState([]);
const [curPage, setCurPage] = useState(0);

const fetchItem = useCallback(async ()=>{
  const data = await callAPI(); // data is an object

  setList(prev => [...prev, data]);
},[]);

useEffect(()=>{
  if(list.length - 1 < curPage) {
    fetchItem().then(()=>{
      // some operations
    });
  } else {
      // some operations
  }

},[curPage, fetchItem]); // eslint will throw a warning: React Hook useEffect has a missing dependency: 'list.length'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)

ESlint will throw a warning because I didn’t put list in dependencies array, but it was used in the effect.

But if I put list or list.length in dependencies array, the effect will execute repeatedly because the fetchItem will update list.

I tried to add a ref to store list.length, but I think it’s unconventional.

Is there any better and elegant way to handle this kind of situations when an effect depends on a state which will update during the execution of the effect?

2

Answers


  1. To execute your code when a component mounts, you need to write it in the body of useEffect. Additionally, if you want your code to be executed when the component updates, you should specify the dependencies that trigger its execution. When any of the dependent values change, the code inside useEffect will run again.

    you can test this code :

    useEffect(()=>{
      if(list.length - 1 < curPage) {
        fetchItem().then(()=>{
          // some operations
        }
      } else {
          // some operations
      }
    },[dependencies])
    
    Login or Signup to reply.
  2. You’ll need to add a check within useEffect to see if the fetch is necessary and, if not, exit without fetching again. You can store information about the last fetch and then use that in the condition.

    For example:

    const lastFetchedPageRef = useRef(-1);
    
    const listLength = list.length;
    
    useEffect(() => {
      if (lastFetchedPageRef.current != curPage && listLength - 1 < curPage) {
        // ...
        lastFetchedPageRef.current = curPage;
      }
    }, [curPage, listLength, fetchItem]);
    

    Note that I’ve used a ref for lastFetchedPageRef because updating that value doesn’t need to cause a rerender.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search