簡體   English   中英

ReactJS:useMemo 鈎子解決了我的無限重新渲染問題而不是 useEffect

[英]ReactJS : useMemo hook fixed my infinite rerender issue instead of useEffect

沒有 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. 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 我嘗試尋找解決方案,但我什至不知道我的問題出在哪里。 非常感謝任何建議。 謝謝

您可以將其值存儲在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 文件中)。 如果您刪除該包裝器,將停止額外的重新渲染。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM