Without useMemo : infinite rerendering component

我在成功编译以下代码时遇到了问题,但是无限次地重新呈现组件,并且在控制台中收到以下错误: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;

因此,我try 将useEffect挂钩与更改筛选器(ActiveFilter)的依赖项一起使用,这将导致组件仅重新呈现一次,但它没有.我try 使用useCallback挂钩,因为setState是异步的,但没有帮助.



With useMemo : issue seems "fixed"

然后我认为这与filteredAllFaqarray.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);

Even though it fixed the rerendering issue, I feel like I'm using it the wrong way and the whole component could be done much better.

There's also a small issue after my "fix" because it seems to render/console.log(activeFilter) exactly 4 times at mount and whenever 100 changes. I was expecting it to render only once.

我的react 是新的,以前从未用过useMemo.我试着寻找解决办法,但我甚至不知道我的问题出在哪里.如有任何建议,我们将非常感激.谢谢

推荐答案

您可以将其值存储在useState挂钩中,而不是在函数体中将filteredAllFaq定义为const.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]);

考虑到useEffectfilteredAllFaq依赖关系已被移除,并且activeFilter依赖关系足以更新filteredAllFaq状态.


至于console.log人被执行四次的情况.这些额外的重现可能是reactStrictMode的结果,它围绕着主项目组件(通常位于index.js文件中).如果您移除该包装,额外的重现器将被停止.

Reactjs相关问答推荐

InfiniteScroll持续获取数据,直到超过最大更新深度

Shadck/ui Select -当用户 Select 项目时更改状态

值在返回页面时不更新,即使我已经更新了它们

获取未捕获的错误:Gatsby生产版本上的最小化react 错误#418

使用Ionic 7和React 18,如何访问历史对象以在页面之间导航?

滚动视图样式高度没有任何区别

.populate() 方法在 mongodb 中不起作用

找不到名称setCometChat

将 useRef 与 useImperativeHandle 一起使用时,React 不会重新渲染

如何更新redux状态存在的输入框

在按钮单击中将动态参数传递给 React Query

在 React JS 中编辑表格数据

如何在 React Native 中更新跨屏幕呈现的上下文状态变量?

DatePicker MUI 如何在日历左侧显示清除文本

使用 React.lazy 调试 webpack 代码拆分

React CSSTransition 两次创建新页面并在这两个相同的页面上运行转换

React Native PermissionsAndroid 不包括 READ_MEDIA_IMAGES.如何解决这个问题?

当用户输入相同信息时如何禁用更新

错误:无效挂钩调用.钩子只能在函数组件的主体内部调用.使用 next/router 时

如何在组件文件夹内的react 组件文件中导入外部css文件?