简体   繁体   English

React useState hook 导致无限渲染

[英]React useState hook causes infinite rendering

I'm listing all products according to the search query.我根据搜索查询列出所有产品。 I store all brands and sellers information of listed products in useState hook.我将列出产品的所有品牌和卖家信息存储在 useState 挂钩中。 Which until this point it works.直到现在它才有效。 Now I want to store all categories in useState hook.现在我想将所有类别存储在 useState 挂钩中。

listProducts are the listed version of results. listProducts 是列出的结果版本。 Thoose results can be sorted or filtered seperately by user.这些结果可以由用户单独排序或过滤。 And defaultProducts will not be effected.并且 defaultProducts 不会受到影响。 defaultProducts is what I get from the database. defaultProducts 是我从数据库中得到的。

  const { query } = useParams();
  const [products, setProducts] = useState([]);
  const [listProducts, setListProducts] = useState([]);
  const [brands, setBrands] = useState([]);
  const [sellers, SetSellers] = useState([]);
  const [Categories, setCategories] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    setIsLoading(true);
    
    axios
      .get(`/api/product/search/${query}`)
      .then((res) => res.data)
      .then((data) => {
        setIsLoading(false);
        setProducts(data.products);
        setListProducts(data.products);

        if (data.products.length < 1) {
          setProducts(data.brands);
          setListProducts(data.brands);
        }
      });
  }, [query]);

  useEffect(() => {
    let brandSet = new Set();
    let sellerSet = new Set();
    let categoriesSet = new Set();

    products.forEach((item) => {
      categoriesSet.add(item.category);
      categoriesSet.add(item.subCategory);
      brandSet.add(item.brand);
      sellerSet.add(item.shop.companyName);
    });

    setCategories([...categoriesSet]);
    setBrands([...brandSet]);
    SetSellers([...sellerSet]);
  }, [products]);

And I finally render ProductFilters component.最后我渲染ProductFilters组件。

 <ProductFilters
   DefaultProducts={products}
   ListProducts={listProducts}
   Brands={brands}
   Sellers={sellers}
   Categories={Categories}
   setListProducts={setListProducts}
   Brand={brand}
 />

In ProductFilters.jsProductFilters.js

<FilterTypeSection className="mt-3">
        <FilterType>Categories</FilterType>
        <CategoriesSection>
          {Categories.map((categoryItem, index) => {
            return (
              <CategoryItem
                key={index}
                onClick={
                  category === categoryItem
                    ? setCategory("")
                    : setCategory(categoryItem)
                }
                style={
                  categoryItem === category
                    ? { fontWeight: "bold", color: "black" }
                    : { fontWeight: "normal", color: "var(--text-muted)" }
                }
              >
                {categoryItem}
              </CategoryItem>
            );
          })}
        </CategoriesSection>
</FilterTypeSection>

I listed sellers and brands data like above and they worked.我像上面一样列出了卖家和品牌数据,他们工作了。 But when I added this code I got this error:但是当我添加这段代码时,我得到了这个错误:

Unhandled Rejection (Error): Too many re-renders. React limits the number of renders to prevent an infinite loop.
▶ 18 stack frames were collapsed.
(anonymous function)
src/pages/searchResultsPage.js:162
  159 |   sellerSet.add(item.shop.companyName);
  160 | });
  161 | 
> 162 | setCategories([...categoriesSet]);
      | ^  163 | setBrands([...brandSet]);
  164 | SetSellers([...sellerSet]);
  165 | 

Even if I set a default value for Categories prop like Categories=["a","b","c"] I still get same error.即使我为Categories Categories=["a","b","c"]类的 Categories 属性设置了默认值,我仍然会收到相同的错误。

Issue问题

In your onClick function you are doing a function call setCategory("") .在您的 onClick function 中,您正在执行 function 调用setCategory("") But what you need is a just a function signature which can be called at a later time when the user clicks it.但是您需要的只是一个 function 签名,可以在以后用户单击它时调用。

so change your onClick as an inline function.所以将您的 onClick 更改为内联 function。

onClick={() => {
  category === categoryItem
  ? setCategory("")
  : setCategory(categoryItem)
}

The setCategory function will be called again and again if you don't use arrow function there.如果您不在那里使用箭头 function,那么setCategory function 将被一次又一次地调用。 Your ProductFilters component should be like this:您的ProductFilters组件应如下所示:

<FilterTypeSection className="mt-3">
    <FilterType>Categories</FilterType>
    <CategoriesSection>
        {Categories.map((categoryItem, index) => {
            return (
              <CategoryItem
                key={index}
                onClick={
                  () => category === categoryItem
                    ? setCategory("")
                    : setCategory(categoryItem)
                }
                style={
                  categoryItem === category
                    ? { fontWeight: "bold", color: "black" }
                    : { fontWeight: "normal", color: "var(--text-muted)" }
                }
              >
                {categoryItem}
              </CategoryItem>
            );
        })}
    </CategoriesSection>
</FilterTypeSection>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM