Reputation: 360
I'm using useEffect
to fetch data from DB and later the code displays that list of data.
useEffect(() => {
console.log("triggered")
fetch("http://localhost:8080/group/getAll")
.then(response => response.json())
.then(data => {
setGroups(data)
})
})
I noticed that triggered
got printed to console thousands of times in a couple seconds so I'm assuming it's constantly sending request to the DB.
Is this the expected behavior? And if not, how to I fix it?
p.s. I know with the []
parameter it only renders once. But is there a way to make useEffect work correctly (only fetch data when groups
rerenders on the webpage)
-----edit-----
This is how I used groups
const createGroup = groups.map((group, i) => {
return (
<Dropdown.Item
key = {i}
onClick = {showUser}
id = {group["groupId"]}
>
{group["groupName"]}
</Dropdown.Item>
)
})
And createGroup
<Dropdown.Menu>
{createGroup}
</Dropdown.Menu>
----edit2-------
I understand how dependency arrays work. I tried [groups]
but that didn't change anything. I also tried [createGroup]
but got an error because the function was not initialized at first. Can I add an HTML element or something to the dependency array? With the structure of my code what exactly should I put in there?
Upvotes: 0
Views: 1708
Reputation: 153
I believe you should understand component lifecycle concepts first (probably with class components), then understand how lifecycle can be replicated with hooks and functional components.
I put here an explanation, I hope this explanation could be helpful.
Please, compare these three snippets:
Snippet #1:
// This snippet (#1) runs on every render because there is no dependencies.
// So if the component gets updated then it will be re-rendered.
// Consequently, this effect will be fired again (and again if the effect updates the component state).
useEffect(() => {
// fetch logic [...]
console.log("runs every time component is re-rendered");
});
Snippet #2:
// This snippet (#2) runs on mount. It's similar to componentDidMount on class components.
// Notice there is an empty array of dependencies as a second argument.
// You can fetch data when page is loaded with this snippet.
useEffect(() => {
// fetch logic [...]
console.log("runs only when component was mounted");
}, []);
Snippet #3:
// This snippet (#3) runs when values on dependency array change, like url variable.
// You can select your array of dependencies. Be aware when some dependency gets updated.
useEffect(() => {
console.log("triggered only when dependencies change")
fetch(url)
.then(response => response.json())
.then(data => {
setGroups(data)
})
}, [url]);
Have a great day!
Upvotes: 1
Reputation: 882
Regarding:
I noticed that triggered got printed to console thousands of times in a couple seconds so I'm assuming it's constantly sending request to the DB.
This has already been answered, and no, for your use case, this isn't the expected behavior since you seem to want to fetch data from the DB,
fetch("http://localhost:8080/group/getAll")
collect the JSON,
.then(response => response.json())
and set a state variable using setGroups
.then(data => {
setGroups(data)
})
That said, regarding:
But is there a way to make useEffect work correctly (only fetch data when groups rerenders on the webpage)
How do you want the useEffect
to work correctly ?
Per its usage in your code, it seems to working as designed. If you want to trigger a re-render using useEffect
you are going to want another state variable other than groups
, which, as many commentators and users pointed out, is going to cause an infinite loop.
Ask yourself: Do you want the API call to be made again? (and hence the re-render) based on the selection of a group
from <Dropdown>
?
Then the value that was selected in the <Dropdown>
needs to be passed to the dependency array of useEffect
Upvotes: 1
Reputation: 9284
You should specify, the state variables or the props, which when changed should trigger the useEffect, like this:
useEffect(() => {
console.log("triggered")
fetch("http://localhost:8080/group/getAll")
.then(response => response.json())
.then(data => {
setGroups(data)
})
}, [x , y]);
Here x
and y
, can be state variables, props, or both. Only when the values of these will change, then the useEffect will trigger.
Upvotes: 2