如何修复React组件AnvendelsesDisplay的无限渲染循环问题
React组件无限循环问题排查与修复
问题现象
React视图触发无限循环,报错信息如下:
Too many re-renders. React limits the number of renders to prevent an infinite loop. renderWithHooks@http://localhost:3000/static/js/bundle.js:30378:19
问题出在AnvendelseDisplay组件,相关代码如下:
import { useState, useEffect } from "react" import { Container } from 'react-bootstrap'; import BBRMapping from "./BBRMapping"; const AnvendelseDisplay = ({type, anvendelse}) => { const [ a, setA ] = useState(0); const bbrmap = new BBRMapping(); const val = bbrmap.MapBBRCode(type, anvendelse); setA(val); return ( <> <p>Anvendelse: {a}</p> </> ); } const ResultsDisplay = (props) => { const hest = props.hest; const bbrmap = new BBRMapping(); return( <> <Container> <h2>Grund</h2> <p>Grundareal: {hest.grund.grundareal.grundareal} kvm</p> <p>BFE-nummer: {hest.grund.grundareal.bfeNummer}</p> </Container> {hest.enheder.map((h, i) => { return( <Container> <h2>Enhed</h2> <p>Enhedensanvendelse: {h.enh020EnhedensAnvendelse}</p> <p>Antal vaerelser: {h.enh031AntalVærelser}</p> <p>Antal badevaerelser: {h.enh066AntalBadeværelser}</p> <p>Antal vandskyllede toiletter: {h.enh065AntalVandskylledeToiletter}</p> <p>Boligtype: {bbrmap.MapBoligtype(h.enh023Boligtype)}</p> <p>Enhedens samlede areal: {h.enh026EnhedensSamledeAreal}</p> <p>Areal til beboelse: {h.enh027ArealTilBeboelse}</p> <p>Toiletforhold: {bbrmap.MapToiletforhold(h.enh032Toiletforhold)}</p> <p>Badeforhold: {bbrmap.MapBadeforhold(h.enh033Badeforhold)}</p> <p>Koekkenforhold: {bbrmap.MapKoekkenforhold(h.enh034Køkkenforhold)}</p> <p>Energiforsyning: {bbrmap.MapEnergiforsyning(h.enh035Energiforsyning)}</p> </Container> ) })} {hest.bygninger.map((h, i) => { return( <Container> <h2>Bygning</h2> <AnvendelseDisplay anvendelse={h.byg021BygningensAnvendelse} type="BygAnvendelse" /> <p>Tagdaekningsmateriale: {bbrmap.MapTagdaekningsmateriale(h.byg033Tagdækningsmateriale)}</p> <p>Ydervaeggens materiale: {bbrmap.MapYdervaeggensMateriale(h.byg032YdervæggensMateriale)}</p> <p>Samlede boligareal: {h.byg039BygningensSamledeBoligAreal}</p> <p>Varmeinstallation: {bbrmap.MapVarmeinstallation(h.byg056Varmeinstallation)}</p> <p>Opfoerelsesaar: {h.byg026Opførelsesår}</p> <p>Antal etager: {h.byg054AntalEtager}</p> <p>Koordinat: {h.byg404Koordinat} (Koordinatsystem: {h.byg406Koordinatsystem})</p> <p>Bebygget areal: {h.byg041BebyggetAreal}</p> </Container> ); })} </> ); } export default ResultsDisplay;
BBRMapping.MapBBRCode()的实现:
MapBBRCode(domain, key) { fetch(`/bbrkode/${domain}/${key}`) .then((response) => response.json()) .then((data) => { console.log(`MapBBRCode: ${data.value}`); return data.value; }) }
问题原因
- 无限循环触发逻辑:
AnvendelseDisplay组件在渲染阶段直接调用setA(val),每次组件渲染都会执行状态更新,状态更新又会触发组件重新渲染,形成闭环循环。 - 异步函数返回值无效:
MapBBRCode内部使用异步fetch,但没有返回Promise,导致val实际为undefined,且无法正确获取异步请求结果。
修复方案
步骤1:修正MapBBRCode函数,返回Promise
让函数返回fetch的Promise链,以便组件能正确处理异步结果:
MapBBRCode(domain, key) { return fetch(`/bbrkode/${domain}/${key}`) .then((response) => response.json()) .then((data) => { console.log(`MapBBRCode: ${data.value}`); return data.value; }) }
步骤2:用useEffect包裹状态更新逻辑
将异步请求和状态更新放到useEffect中,仅当依赖项变化时执行,避免重复渲染:
const AnvendelseDisplay = ({type, anvendelse}) => { const [ a, setA ] = useState(0); useEffect(() => { const fetchAndUpdate = async () => { const bbrmap = new BBRMapping(); const val = await bbrmap.MapBBRCode(type, anvendelse); setA(val); }; fetchAndUpdate(); }, [type, anvendelse]); // 仅当type或anvendelse变化时执行 return ( <> <p>Anvendelse: {a}</p> </> ); }
说明
useEffect的依赖数组确保只有当输入参数type或anvendelse改变时,才会重新发起请求并更新状态,彻底切断无限循环的触发条件。- 使用
async/await处理异步请求,让逻辑更清晰,也能正确捕获fetch返回的结果。
内容的提问来源于stack exchange,提问作者Anders
相关产品推荐
相关产品推荐

