ReactJS:useMemo 挂钩修复了我的无限重新渲染问题,而不是 useEffect

问题描述 投票:0回答:1

不使用 useMemo :无限重新渲染组件

我在成功编译下面的代码时遇到问题,但无限次地重新渲染组件,并且在控制台中收到此错误:

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

import { Box, Flex } from "@chakra-ui/react";
import { useEffect, useState } from "react";
import Section, { SectionHeading } from "../../components/UI/Section";

import FaqList from "../../data/FaqList";
import FAQFilterBtn from "./FAQFilterBtn";
import FAQItems from "./FAQItems";

const allFaqItems = Object.values(FaqList).map((elem) => elem.content);

const allFaq = allFaqItems.map((elem, index) => (
  <Box key={index}>
    <FAQItems items={elem} faqHeading={Object.values(FaqList)[index].heading} />
  </Box>
));

const FAQSection = () => {
  const [displayList, setDisplayList] = useState(allFaq);
  const [activeFilter, setActiveFilter] = useState("All");

  const filteredAllFaq = 
      allFaqItems.map((elem, index) => {
        const faq =
          activeFilter === Object.values(FaqList)[index].heading ||
          activeFilter === "All" ? (
            elem.length ? (
              <FAQItems
                items={elem}
                faqHeading={Object.values(FaqList)[index].heading}
              />
            ) : (
              ""
            )
          ) : (
            ""
          );
        return <Box key={index}>{faq}</Box>;
      });

  const changeFilter = (filter: string) => {
    setActiveFilter(filter);
  };

  useEffect(() => {
    setDisplayList(filteredAllFaq);
  }, [activeFilter, filteredAllFaq]);

 
  console.log(activeFilter);

  return (
    <Section id="#faq-section">
      <>
        <Flex w="full" justify="space-between">
          <SectionHeading mb={0}>Frequently asked questions</SectionHeading>
        </Flex>

        <Flex m={4} mb={-4} gap={6}>
          <FAQFilterBtn
            name="All"
            active={activeFilter}
            setFilter={changeFilter}
          />
          {FaqList.map((e, index) => (
            <FAQFilterBtn
              key={index}
              name={e.heading}
              active={activeFilter}
              setFilter={changeFilter}
            />
          ))}
        </Flex>

        {displayList}
      </>
    </Section>
  );
};

export default FAQSection;

因此,我尝试使用

useEffect
钩子,并依赖于更改过滤器 (activeFilter),这会导致组件仅重新渲染一次,但事实并非如此。我尝试使用
useCallback
钩子,因为 setStates 是异步的,但没有帮助。



使用 useMemo :问题似乎“已解决”

然后我认为这与

filteredAllFaq
是一个
array.map()
有关,这可能是一个“昂贵/高负载功能”,所以我决定使用
useMemo
钩子,这似乎解决了这个问题。代码如下:

  const filteredAllFaq = useMemo(() => allFaqItems.map((elem, index) => {
    const faq =
      activeFilter === Object.values(FaqList)[index].heading ||
      activeFilter === "All" ? (
        elem.length ? (
          <FAQItems
            items={elem}
            faqHeading={Object.values(FaqList)[index].heading}
          />
        ) : (
          ""
        )
      ) : (
        ""
      );
    return <Box key={index}>{faq}</Box>;
  }), [activeFilter]);

  const changeFilter = (filter: string) => {
    setActiveFilter(filter);
  };

  useEffect(() => {
    setDisplayList(filteredAllFaq);
  }, [activeFilter, filteredAllFaq]);

  console.log(activeFilter);

尽管它解决了重新渲染问题,但我觉得我使用它的方式是错误的,整个组件可以做得更好。

在我的“修复”之后还有一个小问题,因为它似乎在安装时以及每当

activeFilter
发生变化时渲染/console.log(activeFilter) 正好 4 次。我原以为它只会渲染一次。

我是 React 新手,之前从未使用过

useMemo
。我尝试寻找解决方案,但我什至不知道我的问题出在哪里。非常感谢任何建议。谢谢你

reactjs react-hooks
1个回答
2
投票

您可以将其值存储在

filteredAllFaq
钩子中,而不是在函数体中将
const
定义为
useState
displayList
状态钩子是无用的并且会导致问题。所以将其替换为

const [filteredAllFaq, setFilteredAllFaq] = useState(allFaq);

当您想要更改

filteredAllFaq
值时,请在
useEffect
钩子中进行操作,如下所示(而不是在函数体内):

 useEffect(() => {
    const newFilteredAllFaq = allFaqItems.map((elem, index) => {
      const faq =
        activeFilter === Object.values(FaqList)[index].heading ||
          activeFilter === "All" ? (
          elem.length ? (
            <FAQItems
              items={elem}
              faqHeading={Object.values(FaqList)[index].heading}
            />
          ) : (
            ""
          )
        ) : (
          ""
        );
      return <Box key={index}>{faq}</Box>;
    });
    
    setFilteredAllFaq(newFilteredAllFaq);
  }, [activeFilter]);

考虑到

filteredAllFaq
useEffect
依赖项已被删除,并且
activeFilter
依赖项足以更新
filteredAllFaq
状态。


对于

console.log
执行四次的情况。这些额外的重新渲染可能是
reactStrictMode
的结果,它包裹着主项目组件(通常位于 index.js 文件中)。如果删除该包装器,额外的重新渲染将停止。

© www.soinside.com 2019 - 2024. All rights reserved.