skip to Main Content

I have a relatively simple React view, which currently causes an infinite loop to happen. I try to use useState where ever possible.
Below is the code. it is the component AnvendelsesDisplay that is causing the issue, resulting in the following errors:
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


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.enh066AntalBadevu00e6relser}</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.enh034Ku00f8kkenforhold)}</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.byg033Tagdu00e6kningsmateriale)}</p>
                    <p>Ydervaeggens materiale: {bbrmap.MapYdervaeggensMateriale(h.byg032Ydervu00e6ggensMateriale)}</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;

I was unable to get the AnvendelsesDisplay to work properly.

Code for BBRMapping.MapBBRCode() is here:

    MapBBRCode(domain, key) 
    { 
        fetch(`/bbrkode/${domain}/${key}`)
                .then((response) => response.json())
                .then((data) => {
                        console.log(`MapBBRCode: ${data.value}`);
                        return data.value;
                })

    }

2

Answers


  1. You’re setting state on every render:

    setA(val);
    

    Updating state triggers a re-render, then your code updates state, which triggers a re-render, which updates state, and so on…

    You can use useEffect with an empty dependency array to perform this operation once when the component first loads:

    useEffect(() => {
      const bbrmap = new BBRMapping();
      const val = bbrmap.MapBBRCode(type, anvendelse);
      setA(val);
    }, []);
    

    Edit: Additionally, now that you’ve also included the code for MapBBRCode you appear to not actually be returning anything from that function. Return the Promise from the fetch operation:

    return fetch(...
    

    Then in the consuming code you need to either await that Promise or follow it with a .then() callback. For example:

    useEffect(() => {
      const bbrmap = new BBRMapping();
      bbrmap.MapBBRCode(type, anvendelse).then(val => setA(val));
    }, []);
    

    or:

    useEffect(() => {
      (async () => {
        const bbrmap = new BBRMapping();
        const val = await bbrmap.MapBBRCode(type, anvendelse);
        setA(val);
      })();
    }, []);
    
    Login or Signup to reply.
  2. The reason is simple.

    Every time a state changes, react re-renders. Each time the setA(val) runs, react re-renders, causing the code which calls setA(val) to run again, changing the state yet again, which triggers ANOTHER re-render, that runs the code again and again, producing an infinite loop. To fix this, you might want to add a condition that stops that code from running if state a already has a value, that way, you only run the code the first time. You can also change the state in a useEffect with an empty dependency array, like so:

    useEffect(() => {
      const bbrmap = new BBRMapping();
      const val = bbrmap.MapBBRCode(type, anvendelse);
      setA(val);
    }, []);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search