Kaitlyn Ayres
Kaitlyn Ayres

Reputation: 11

Infinite Loop error inside componentDidUpdate....why?

I am getting this error: Error: 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.

Why? I have my setState wrapped in an if statement to prevent it from causing an infinite loop but apparently that's not the case. Any suggestions on what to look for in order to solve this error?

componentDidUpdate(prevProps: any, prevState: any) {
    if (this.props.submissions !== prevState.submissions) {
        let uniqueOrganizations: any = [];
        let uniqueWindows: any = [];
        if (this.props.submissions !== null) {
            this.props.submissions.filter((submission: any, index: number) => {
                !uniqueOrganizations.some((o: any) => o.organizationId === submission.user.organization.organizationId) && uniqueOrganizations.push(submission.user.organization);
                !uniqueWindows.some((w: any) => w.windowId === submission.window.windowId) && uniqueWindows.push(submission.window);
            });
            this.setState({
                uniqueOrganizations: uniqueOrganizations,
                uniqueWindows: uniqueWindows
            });
        }
    }
}

Upvotes: 0

Views: 49

Answers (2)

David Kayembe
David Kayembe

Reputation: 107

Your if statement doesn't actually compare the previous props to the actual props. You're comparing the previous props to the previous state. See the documentation here

You can try this.

componentDidUpdate(prevProps: any, prevState: any) {
    if (this.props.submissions !== prevProps.submissions) {
        let uniqueOrganizations: any = [];
        let uniqueWindows: any = [];
        if (this.props.submissions !== null) {
            this.props.submissions.filter((submission: any, index: number) => {
                !uniqueOrganizations.some((o: any) => o.organizationId === submission.user.organization.organizationId) && uniqueOrganizations.push(submission.user.organization);
                !uniqueWindows.some((w: any) => w.windowId === submission.window.windowId) && uniqueWindows.push(submission.window);
            });
            this.setState({
                uniqueOrganizations: uniqueOrganizations,
                uniqueWindows: uniqueWindows
            });
        }
    }
}

Upvotes: 2

Joe Lloyd
Joe Lloyd

Reputation: 22353

Protect componentDidUpdate

This happens if you setState inside component did update and don't check that the change is the same.

Any state change will call componentDidUpdate.

So the line

this.setState({
  uniqueOrganizations: uniqueOrganizations,
  uniqueWindows: uniqueWindows
});

will trigger itself infinitely.

Add protection that it doesn't call this setState again.

Some if inside will help

if(prevProps.uniqueOrganizations !== this.props.uniqueOrganizations)

But you're making this very complex. There will be a bunch of && and || statements in the if statement for each of your states.

Alternative Solution

I recommend making functional components and using the new hooks, especially this one useEffect

you can easily use the hooks api to do this with much less trouble since you can tell each hook to fire on a particular change. But you cannot use a class.

Example

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

See the line here }, [count]); this tells this effect to only fire when count changes. that way you don't have to write all these crazy conditions to get your updates to work without infinite looping.

Upvotes: 1

Related Questions