wl2020
wl2020

Reputation: 75

Why does setState cause my React app go into infinite loop?

I am trying to render the following component, which is supposed to take the value of a few account level values and render the subtotal in a div. This is the code

import * as React from 'react';
import { ILiquidiManagerProps } from './ILiquidiManagerProps';
import {AccountValue} from './AccountFields';
import {LiquidTEUR} from './DummyContent';

interface SubtotalState {
    Account?: any,
    SubtotalValue?: any
  }

export default class SubtotalValues extends React.Component<ILiquidiManagerProps, SubtotalState> {
    public constructor(props: ILiquidiManagerProps) {
        super(props);
        this.state = {
            Account: LiquidTEUR.Subcategories.find(item => item.Name == this.props.label),
            SubtotalValue: 0
        }
    }
    
    private getText = data => {
        this.setState({SubtotalValue: data});
    }

    private initiateValue = () => {
        let Account = this.state.Account;
        let subtotal = 0;
        Account.Accounts.map((item) => {
            subtotal += item.Value;
        })
        this.setState({SubtotalValue: subtotal});
    }

    public render(): React.ReactElement<ILiquidiManagerProps> {
        this.initiateValue();
        return(
            <React.Fragment>
            <a className="collapsible" href="#">
                <div 
                    className={`p-2 text-right value ` + this.props.bgColor + ` font-weight-bold ` + this.props.textColor}
                    data-date={this.props.date}
                    data-name={this.props.label}
                >{this.state.SubtotalValue}</div></a>
            <div className="content hidden">
                {this.state.Account.Accounts.map((item, key) => {
                    return <AccountValue key={key} label={item.Value} getValue={this.getText} subtotal={this.state.SubtotalValue} />;
                })}
                <span className="add-pos">&nbsp;</span>
            </div>
            </React.Fragment>
        );
    }
}

This is the error message it generates

Uncaught (in promise) Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

I have tried several different ways of setting the state of the subtotal, but I always seem to be getting the same error, and I am not sure where I am causing an infinite loop.

Upvotes: 1

Views: 1617

Answers (2)

akhtarvahid
akhtarvahid

Reputation: 9769

You shouldn't use setState() inside render method as you are using this.initiateValue();

Because as you know whenever setState() is called re-rendering happens that's the reason it's going for infinite.

If you want to initialize data call inside componentDidMount() or useEffect()

For more understanding, you can refer to Calling setState() in React from render method

Upvotes: 0

Quentin
Quentin

Reputation: 943163

  1. You call this.initiateValue when the component renders.
  2. initiateValue sets the state
  3. Setting the state triggers a render
  4. GOTO 1

You probably want to call initiateValue from componentDidMount instead.

(Or switch to writing a function component and putting it inside a useEffect hook).

Upvotes: 2

Related Questions