Passing an empty array as the second argument to useEffect makes it only run on mount and unmount, thus stopping any infinite loops.
useEffect(() => {
setIngredients({});
}, []);
This was clarified to me in the blog post on React hooks at https://www.robinwieruch.de/react-hooks/
Answer from WhiteFluffy on Stack OverflowPassing an empty array as the second argument to useEffect makes it only run on mount and unmount, thus stopping any infinite loops.
useEffect(() => {
setIngredients({});
}, []);
This was clarified to me in the blog post on React hooks at https://www.robinwieruch.de/react-hooks/
Had the same problem. I don't know why they not mention this in docs. Just want to add a little to Tobias Haugen answer.
To run in every component/parent rerender you need to use:
useEffect(() => {
// don't know where it can be used :/
})
To run anything only one time after component mount(will be rendered once) you need to use:
useEffect(() => {
// do anything only one time if you pass empty array []
// keep in mind, that component will be rendered one time (with default values) before we get here
}, [] )
To run anything one time on component mount and on data/data2 change:
const [data, setData] = useState(false)
const [data2, setData2] = useState('default value for first render')
useEffect(() => {
// if you pass some variable, than component will rerender after component mount one time and second time if this(in my case data or data2) is changed
// if your data is object and you want to trigger this when property of object changed, clone object like this let clone = JSON.parse(JSON.stringify(data)), change it clone.prop = 2 and setData(clone).
// if you do like this 'data.prop=2' without cloning useEffect will not be triggered, because link to data object in momory doesn't changed, even if object changed (as i understand this)
}, [data, data2] )
How i use it most of the time:
export default function Book({id}) {
const [book, bookSet] = useState(false)
const loadBookFromServer = useCallback(async () => {
let response = await fetch('api/book/' + id)
response = await response.json()
bookSet(response)
}, [id]) // every time id changed, new book will be loaded
useEffect(() => {
loadBookFromServer()
}, [loadBookFromServer]) // useEffect will run once and when id changes
if (!book) return false //first render, when useEffect did't triggered yet we will return false
return <div>{JSON.stringify(book)}</div>
}
For loop inside useEffect (unobvious behaviour)
How to use useEffect and for loop to generate multiple JSX elements
Infinite loop in useEffect using blank object or array
useEffect causes an infinite loop?
Videos
Hey!! First time building a website and have ran into this issue when trying to fetch content from Sanity Studio.
Here's the link: https://pastebin.com/3iL0gpBt
Copying what I think is the relevant part of the code
export default function IssuesList() {
const [items, setItems] = useState([]);
useEffect(() => {
sanityClient
.fetch(
`*[_type == "issue"] | order(publishedAt desc) {
title,
slug,
description,
frontCover{
asset->{
_id,
url
}
}
}`
)
.then((data) => {
setItems(data);
})
.catch(console.error);
});
return (
<div css={issuesListSx}>
<Frame path={[{ name: "Issues", slug: "/issues" }]}>
<Grid gap={2} columns={[1, null, 2]} className="issuesGrid">
{items.map((issue) => {
return (
<div className="issueItem" key={issue.title}>
<Link to={"/issues/" + issue.slug.current}>
<div>{issue.title}</div>
{issue.frontCover && "asset" in issue.frontCover && (
<img src={issue.frontCover.asset.url} alt="" />
)}
</Link>
</div>
);
})}
</Grid>
</Frame>
</div>
);
}E: Fixed!! Had to add an empty array as a second parameter to useEffect