【问题标题】:useEffect causing component to re-render infinitelyuseEffect 导致组件无限重新渲染
【发布时间】:2022-01-12 10:16:09
【问题描述】:

我正在向心愿单添加项目,一旦添加,我会尝试重新渲染心形图标以在其上显示一个数字,以指示该项目已添加到心愿单。我想要实现的类似于 Twitter 的点赞按钮,当有人点赞帖子时,点赞的数量会立即增加。因此,在我的情况下,当有人喜欢(愿望清单)该产品时,它会增加 Heart 图标顶部的数字。我正在使用本地存储来获取添加到愿望清单的项目,当在效果中添加新项目时,我可以重新渲染愿望清单组件,但它会使组件无限重新渲染,这给了我一个警告的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 的第二个参数中输入您想要重新运行的值。
  • 你告诉 React 只在愿望清单状态改变时运行 useEffect,但你正在改变 useEffect 中的愿望清单状态。因此,当您第一次更改愿望清单时,useEffect 会运行,因为愿望清单已更改,但随后 useEffect 已更改愿望清单,这会触发它一次又一次地运行。
  • useEffect 将在“wishlist”更改时重新渲染您的组件,并且您正在通过调用“setWishlist”更改 useEffect 中“wishlist”的值。这就是它陷入无限循环的原因

标签: javascript reactjs react-hooks local-storage


【解决方案1】:

在这里,您在 useEffect 的依赖数组中添加了 wishlist ,并且您添加了条件 if (wishlistStorage.length > 0) { setWishlist(wishlistStorage); } ,因为再次设置愿望清单将导致重新渲染并再次触发 useEffect。

【讨论】:

    【解决方案2】:

    只需从依赖项中删除愿望清单

         React.useEffect(() => {
         if (typeof window !== "undefined") {
           const wishlistStorage =
           localStorage.getItem("wishlist") === null
           ? []
           : [...JSON.parse(localStorage.getItem("wishlist"))];
    
         if (wishlistStorage.length > 0) {
           setWishlist(wishlistStorage);
      }
    }
    
    
    }, []);
    

    【讨论】:

    • 从依赖数组中删除愿望清单,当我向愿望清单添加新内容时,愿望清单计数不会增加,除非我刷新页面。但是,从愿望清单中删除项目会减少愿望清单中的数量
    【解决方案3】:

    如果我理解正确,并且您只需要在初始渲染时使用它,那么您可以简单地从依赖数组中删除 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);
         }
      }
    }, []);
    

    【讨论】:

    • 当我从依赖数组中删除愿望清单时,当我向愿望清单添加新内容时,愿望清单计数不会增加,除非我刷新页面。但是,从愿望清单中删除项目会减少愿望清单中的数量
    • TBH 它真的归结为你的comp的结构。我们通常想要做的是在添加/删除项目时更新相关状态,而不是在useEffect 中。 useEffect 通常用于对更改采取行动,而不是诱导它。
    【解决方案4】:

    您可以从依赖数组中删除愿望清单变量。

    当你调用setWishlist时,它会更新状态,依赖数组会检查它是否已经改变并再次调用useEffect,从而无限循环。

    如果依赖项数组为空,它只会在您的组件挂载、从本地存储中获取数据并初始化您的应用程序时运行。从那里开始,您只需要在本地处理状态并使用任何新的愿望清单项目更新本地存储,但 useEffect 似乎仅用于初始化。

    更新 #1

    这里的核心问题是 OP 使用 LocalStorage 在组件之间传输数据,这不是正确的做事方式。如果您碰巧偶然发现了 OP 的问题并且您正在这样做,请务必研究一下有关在组件之间共享数据的知识。 最常见的方式是 Context API、Redux 以及将数据作为 props 向下传递。

    您可以阅读有关上下文here 的更多信息。

    【讨论】:

    • 是的,但是每当将商品添加到愿望清单时,我都需要更新愿望清单计数。就像当您在 Twitter 上单击心形图标时,数字会立即增加,但是当我从依赖关系数组中删除愿望清单时。我需要刷新才能看到正确的数字
    • 呃,你是从另一个组件/页面更新本地存储吗?如果是这样,那不是正确的方法。尝试查看上下文 API、redux 或将其作为道具传递。
    • 如果您从同一个组件更新愿望清单,只需在单击心脏调用处理程序时调用 setWishList。没有必要为此目的使用 useEffect
    • 正如您所建议的,通过使用 Redux for wishlist 解决了这个问题
    • 干得好!我会说 Context API 是一种更现代的方法,但 redux 工作得很好!也许稍后再看一下,然后选择最适合您的方法
    【解决方案5】:

    你使用wishlist作为useEffect钩子的deps,当wishlist缓存存在时,wishlistStorage是从本地存储JSON字符串解析的对象。然后,你调用setWishlist(wishlistStorage),导致钩子重新渲染,wishlist 将有一个新的引用。 useEffect 将在其依赖项更改时再次执行。这就是无限重新渲染的原因。

    你可以使用lazy initial state

    initialState 参数是初始渲染期间使用的状态。在随后的渲染中,它被忽略。如果初始状态是昂贵计算的结果,您可以提供一个函数,该函数仅在初始渲染时执行

    如果存在,则使用本地存储中的缓存来初始化您的状态,否则返回默认值。

    例如:

    const [wishlist, setWishlist] = React.useState(() => {
     if (typeof window !== "undefined") {
        const wishlistStorage =
           localStorage.getItem("wishlist") === null
           ? []
           : [...JSON.parse(localStorage.getItem("wishlist"))];
        return wishlistStorage;
      }
      return [];
    );
    

    【讨论】:

      【解决方案6】:

      您在 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 上单击心形图标时,数字会立即增加,但是当我从依赖关系数组中删除愿望清单时。我需要刷新才能看到正确的数字
      猜你喜欢
      • 2022-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多