Home > Software engineering >  How can i avoid an infinite loop in my useEffect?
How can i avoid an infinite loop in my useEffect?

Time:05-11

I'm working in a functional component called TaskComponent, where i have this useEffect:

useEffect(() => {
    const getFilterTasks = () => {
      onSnapshot(q, (QuerySnapshot) => {
        QuerySnapshot.forEach((doc) => {
          filteredTasks.push(doc.data())
          console.log(filteredTasks);
        })
        setTasks(filteredTasks);
        })
      }
    
    getFilterTasks();

}, [])
   
  

In my component i have a Flatlist where tasks-state is my data for the Flatlist, so i want to render my component everytime tasks changes and it changes everytime i navigate from my TaskComponent to CategoryComponent and back to TaskComponent again, because the filtered tasks is different based on which category i select. The concept is illustrated in the following three picture:

enter image description here enter image description here enter image description here

And obviously adding ''tasks'' to my dependecy array doesn't work because of the infinite loop it will create because i'm calling setTasks in the useEffect as well.

So i'm not sure have i can solve this, is there a tricky way to solve this, do I have to rerender my component or something completely different?

CodePudding user response:

EDIT: The question is solved now, i just added the item.id in the dependency array.

This is how i have done with the refresh/setRefresh state:

  useEffect(() => {
    const getFilterTasks = async() => {
    const q = query(collection(db, 'allTasks'), where('userID', '==', userID), where('categoryID', '==', item.id))
    const querySnapshot = await getDocs(q);
    querySnapshot.forEach((doc) => {
      filteredTasks.push(doc.data())
    })
    setTasks(filteredTasks)
    }

    getFilterTasks();

    setRefresh(false)
    console.log(refresh)

  }, [refresh])


  const handleRefresh = () => {
    setRefresh(true);
  }

I have added the: const [refresh, setRefresh] = useState(false);

And then i have a button that is connected to handleRefresh.

This works, but it is not a beautiful way to do it.

CodePudding user response:

First of all, you have to know that useEffect combines componentDidMount, ComponentDidUpdate and componentWillUnmount.

So, if you need it to work just one time when your component renders (commponentDidMount Approach):

  • Recommended if you're fetching data from API

  • Your array of dependencies should be empty

useEffect( () => {
  set Your Logic here
  
}, [])

If you need to keep watching changes for some variables/ states (ComponentDidUpdate Approach):

  • Recommended If you want to update some parts of your component based on a variable that might change in run time
  • Pass the variables that you want to watch in the array of dependencies

useEffect(()=>{

  set Your Logic here

},[yourDependencies])

Finally, if you want to run a cleanup function when you're leaving a component to prevent memory leaks and unwanted behaviors in your application (componentWillUnmount Approach):

useEffect(()=>{
 
 set Your Logic here

  return () => {
            cleanup
        }

},[])

  • Related