Teos Verdi
Teos Verdi

Reputation: 85

React component loops updating (GraphQL)

Good day! I keep getting

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.

which looks obvious, but i fail to see the loop in my component.

ComponentWillUpdate() shows that it calls lots of rerender with the same props and state in a short amount of time.

Thanks in advance.

src/TitleList.js

class TitleList extends Component {
    constructor(props) {
        super(props)
        this.state = {'items': null}
    }
     onSortEnd = ({oldIndex, newIndex}) => {
        this.setState({
             items: arrayMove(this.state.items, oldIndex, newIndex),
         });
     };
    render() {
        if (this.props.allTitlesQuery && this.props.allTitlesQuery.loading){
            return <div>Loading</div>
        }
        if (this.props.allTitlesQuery && this.props.allTitlesQuery.error) {
            return <div>Error!</div>
        }
        const titlesToRender = this.props.allTitlesQuery.allTitles
        this.setState({'items': titlesToRender})
        return <SortableList
            items={this.state.items}
            onSortEnd={this.onSortEnd}
        />;
    }
}

Upvotes: 0

Views: 755

Answers (3)

Harkirat Saluja
Harkirat Saluja

Reputation: 8114

When you call this.setState it calls your renderagain. So if you call setState from render it goes to recursive loop.

You can try something as :-

class TitleList extends Component {
    constructor(props) {
        super(props)
        this.state = {'items': null}
    }
    componentDidMount () {
        this.updateState(props);
    }

    componentWillReceiveProps (nextProps) {
        if (this.props.allTitlesQuery.allTitles !== nextProps.allTitlesQuery.allTitles) {
        this.setState(nextProps);
      }
    }

    updateState (props) {
        this.setState({"items":props.allTitlesQuery.allTitles});
    }

     onSortEnd = ({oldIndex, newIndex}) => {
        this.setState({
             items: arrayMove(this.state.items, oldIndex, newIndex),
         });
     };
    render() {
        if (this.props.allTitlesQuery && this.props.allTitlesQuery.loading){
            return <div>Loading</div>
        }
        if (this.props.allTitlesQuery && this.props.allTitlesQuery.error) {
            return <div>Error!</div>
        }
        return <SortableList
            items={this.state.items}
            onSortEnd={this.onSortEnd}
        />;
    }
}

Use componentDidMount method to render the data for first time and if data changes update using componentWillReceiveProps method

Upvotes: 2

brub
brub

Reputation: 1153

You shouldn't be calling setState inside of render, do it in another lifecycle method like componentDidMount or componentWillReceiveProps:

Render shouldn't modify state: https://reactjs.org/docs/react-component.html#render

Upvotes: 1

Littlee
Littlee

Reputation: 4327

the loop is caused by this.setState({'items': titlesToRender}) in your render function

Upvotes: 2

Related Questions