Nathan
Nathan

Reputation: 360

React useEffect non-stop fetching

I'm trying to fetch some data from the backend and display those data in a dropdown menu.

  const[allGroups, setAllGroups] = useState([])

  useEffect(() => {
    console.log("useEffect")
    // get all Groups
    fetch("http://localhost:8080/group/getAll")
      .then(response => response.json())
      .then(data => {
        let arr = []
        for (let i = 0; i < data.length; i++){
          arr.push(data[i]["groupName"])
        }
        setAllGroups(arr)
      })
  }, [allGroups])

And this is where I generate things

<Dropdown.Menu>
  <Dropdown.Item href="#/action-1">Action</Dropdown.Item>
  {
    allGroups.map((group, i) => {
      return (
        <Dropdown.Item key={i}>{group}</Dropdown.Item> 
      )
    })
  }
</Dropdown.Menu>

I noticed the useEffect hook was running basically all the time (even if the value of allGroups didn't change). I thought useEffect only runs when the specified elements on the page rerender. Is there a way to only trigger useEffect when allGroups change? Thanks!

Upvotes: 1

Views: 1418

Answers (3)

Amr Khaled
Amr Khaled

Reputation: 457

by using allGroups inside the useEffect the useEffect will be re-render the component as long the allGroups change.

you just need to fetch the APIS in the first render for the component that will lead you to just use useEffect with empty dependency like this []. after getting the response just update the state by using setAllGroups. then implement what you need on allGroups

 const[allGroups, setAllGroups] = useState([])

  useEffect(() => {
    console.log("useEffect")
    // get all Groups
    fetch("http://localhost:8080/group/getAll")
      .then(response => response.json())
      .then(data => {
        setAllGroups(data) <= just update the state with the response here.
      })
  }, []) <= you don't need to add **allGroups** here

Upvotes: 0

Donut
Donut

Reputation: 112825

Is there a way to only trigger useEffect when allGroups change?

That's exactly what your code is doing already. However, allGroups is changing each time the function is run (since you're calling setAllGroups as part of that function).

If you only want the items to be fetched once (after component's first render), remove allGroups from the deps array.

If you want to re-fetch the data in response to some user action, define a separate method that can be explicitly called, and then call it appropriately (e.g. when a button is clicked) in addition to calling it within useEffect with an empty deps array.

Upvotes: 2

Ayoub Rouani
Ayoub Rouani

Reputation: 16

Just remove allGroups params from useEffect dependencys

this happened because on each render you fetch your data and when fetch success you set new data to all Groups state that make useEffect rerender

  const[allGroups, setAllGroups] = useState([])

  useEffect(() => {
      getAllGroups()
  }, [])


const getAllGroups = () => {
    fetch("http://localhost:8080/group/getAll")
      .then(response => response.json())
      .then(data => {
        let arr = []
        for (let i = 0; i < data.length; i++){
          arr.push(data[i]["groupName"])
        }
        setAllGroups(arr)
      })
}

Upvotes: 0

Related Questions