[英]ReactJS : useMemo hook fixed my infinite rerender issue instead of useEffect
我遇到了以下代碼編譯成功但重新渲染組件無限次的問題,我在控制台中收到此錯誤: 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 是異步的,但它沒有幫助。
然后我認為這與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]);
考慮到useEffect
的filteredAllFaq
依賴已被移除, activeFilter
依賴足以更新filteredAllFaq
狀態。
至於console.log
執行四次的情況。 這些額外的重新渲染可能是reactStrictMode
的結果,它包裹在主要項目組件(通常位於 index.js 文件中)。 如果您刪除該包裝器,將停止額外的重新渲染。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.