useEffect 导致组件无限重新渲染
useEffect causing component to re-render infinitely
我正在将项目添加到心愿单中,一旦添加,我将尝试重新渲染心形图标以在其上添加一个数字,以指示该项目已添加到心愿单中。我想实现的是类似于Twitter的点赞按钮,当有人点赞post时,点赞数立即增加。所以,在我的例子中,当有人喜欢(愿望清单)产品时,它会增加心脏图标顶部的数字。我正在使用本地存储来获取添加到心愿单的项目,当在效果中添加新项目时,我可以重新渲染心愿单组件,但它会使组件无限地重新渲染,这给了我一个警告共 Warning: Maximum update depth exceeded
这是我的效果;
const [wishlist, setWishlist] = React.useState([]);
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, [wishlist]);
如果我从依赖数组中删除心愿单,我需要刷新页面才能看到正确的项目数。我在这里做错了什么以及解决这个问题的最佳方法是什么。谢谢!
这里你在 useEffect 的依赖数组中添加了 wishlist 并且你添加了条件 if (wishlistStorage.length > 0) { setWishlist(wishlistStorage); }
,因为再次设置 wishlist 会导致重新渲染和再次触发useEffect。
只需从依赖项中删除心愿单
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, []);
如果我理解正确,并且您只需要在初始渲染时使用它,那么您可以简单地从依赖项数组中删除 wishlist
。
const [wishlist, setWishlist] = React.useState([]);
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, []);
您可以从依赖项数组中删除心愿单变量。
当你调用setWishlist
时,它会更新状态,依赖数组会检查它是否已经改变,并会再次调用useEffect,从而无限循环。
对于空的依赖项数组,它只会 运行 当您的组件安装时,从您的本地存储中获取数据并初始化您的应用程序。从那时起,您所需要的就是在本地处理状态并使用任何新的愿望清单项目更新本地存储,但 useEffect 似乎仅用于初始化。
更新 #1
这里的核心问题是 OP 使用 LocalStorage 在组件之间传输数据,这不是正确的做事方式。如果您碰巧遇到了 OP 的问题并且您正在这样做,请务必研究一下有关在组件之间共享数据的知识。
最常见的方式是 Context API、Redux 和将数据作为 props 向下传递。
您可以阅读有关上下文的更多信息here。
你使用wishlist
作为useEffect
hooks的deps,当wishlist
缓存存在时,wishlistStorage
是从本地存储解析出来的对象JSON 细绳。然后,你调用 setWishlist(wishlistStorage)
,导致钩子重新渲染,wishlist
将有一个新的引用。 useEffect
将在其依赖项更改时再次执行。这就是无限重新渲染的原因。
你可以使用 lazy initial state
The initialState
argument is the state used during the initial render. In subsequent renders, it is disregarded. If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render
使用本地存储中的缓存来初始化你的状态(如果存在),否则,returns一个默认值。
例如:
const [wishlist, setWishlist] = React.useState(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
return wishlistStorage;
}
return [];
);
你在 useEffect 中使用 setWishlist,这是观察愿望清单,这就是为什么它会导致你进入无限循环,因为当愿望清单值更改时,它会一次又一次地执行 useEffect 中的代码,所以对于我的解决方案,我在 useEffect 中看到了 localStorage 我想它只会在第一次渲染时被检查,所以你可以简单地删除 [wishlist] -> []
const [wishlist, setWishlist] = React.useState([]);
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, []);
我正在将项目添加到心愿单中,一旦添加,我将尝试重新渲染心形图标以在其上添加一个数字,以指示该项目已添加到心愿单中。我想实现的是类似于Twitter的点赞按钮,当有人点赞post时,点赞数立即增加。所以,在我的例子中,当有人喜欢(愿望清单)产品时,它会增加心脏图标顶部的数字。我正在使用本地存储来获取添加到心愿单的项目,当在效果中添加新项目时,我可以重新渲染心愿单组件,但它会使组件无限地重新渲染,这给了我一个警告共 Warning: Maximum update depth exceeded
这是我的效果;
const [wishlist, setWishlist] = React.useState([]);
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, [wishlist]);
如果我从依赖数组中删除心愿单,我需要刷新页面才能看到正确的项目数。我在这里做错了什么以及解决这个问题的最佳方法是什么。谢谢!
这里你在 useEffect 的依赖数组中添加了 wishlist 并且你添加了条件 if (wishlistStorage.length > 0) { setWishlist(wishlistStorage); }
,因为再次设置 wishlist 会导致重新渲染和再次触发useEffect。
只需从依赖项中删除心愿单
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, []);
如果我理解正确,并且您只需要在初始渲染时使用它,那么您可以简单地从依赖项数组中删除 wishlist
。
const [wishlist, setWishlist] = React.useState([]);
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, []);
您可以从依赖项数组中删除心愿单变量。
当你调用setWishlist
时,它会更新状态,依赖数组会检查它是否已经改变,并会再次调用useEffect,从而无限循环。
对于空的依赖项数组,它只会 运行 当您的组件安装时,从您的本地存储中获取数据并初始化您的应用程序。从那时起,您所需要的就是在本地处理状态并使用任何新的愿望清单项目更新本地存储,但 useEffect 似乎仅用于初始化。
更新 #1
这里的核心问题是 OP 使用 LocalStorage 在组件之间传输数据,这不是正确的做事方式。如果您碰巧遇到了 OP 的问题并且您正在这样做,请务必研究一下有关在组件之间共享数据的知识。 最常见的方式是 Context API、Redux 和将数据作为 props 向下传递。
您可以阅读有关上下文的更多信息here。
你使用wishlist
作为useEffect
hooks的deps,当wishlist
缓存存在时,wishlistStorage
是从本地存储解析出来的对象JSON 细绳。然后,你调用 setWishlist(wishlistStorage)
,导致钩子重新渲染,wishlist
将有一个新的引用。 useEffect
将在其依赖项更改时再次执行。这就是无限重新渲染的原因。
你可以使用 lazy initial state
The
initialState
argument is the state used during the initial render. In subsequent renders, it is disregarded. If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render
使用本地存储中的缓存来初始化你的状态(如果存在),否则,returns一个默认值。
例如:
const [wishlist, setWishlist] = React.useState(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
return wishlistStorage;
}
return [];
);
你在 useEffect 中使用 setWishlist,这是观察愿望清单,这就是为什么它会导致你进入无限循环,因为当愿望清单值更改时,它会一次又一次地执行 useEffect 中的代码,所以对于我的解决方案,我在 useEffect 中看到了 localStorage 我想它只会在第一次渲染时被检查,所以你可以简单地删除 [wishlist] -> []
const [wishlist, setWishlist] = React.useState([]);
React.useEffect(() => {
if (typeof window !== "undefined") {
const wishlistStorage =
localStorage.getItem("wishlist") === null
? []
: [...JSON.parse(localStorage.getItem("wishlist"))];
if (wishlistStorage.length > 0) {
setWishlist(wishlistStorage);
}
}
}, []);