Alexander
Alexander

Reputation: 113

React calling a function inside the render method leads to endless call stack

import React, {Component} from 'react'
import ajax from '../confing/ajax'
import $ from 'jquery'

class Categories extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isActive: '',
            categories: ''
        };
        this.switchLinkToActive = this.switchLinkToActive.bind(this);
    }

    switchLinkToActive(event) {
        event.preventDefault();
        let temp = [];
        console.log(event.target.id);
        for (let i = 0; i < this.state.isActive.length; i++) {
            if (i === parseInt(event.target.id)) {
                temp[i] = true;
            } else {
                temp[i] = false;
            }
        }
        this.setState({
            isActive: temp
        })

    }

    func() {
        let categories = [];
        ajax.request.get('categories').then((resp) => {
            let isActive = new Array(resp.length);
            for (let i = 0; i < resp.length; i++) {
                isActive[i] = false;
            }
            this.setState({
                isActive: isActive
            });
            for (let i = 0; i < resp.length; i++) {
                let element = resp[i];
                categories.push(<a key={element.id} href=""
                                   className={this.state.isActive[i] === true ? "list-group-item list-group-item-action active" : "list-group-item list-group-item-action"}
                                   id={i} onClick={this.switchLinkToActive}>{element.name}</a>);

            }
            this.setState({
                categories: categories
            });
        });
    }

    render() {
       this.func();
        return (
            <div className="list-group col-3">
                {/*{this.state.categories}*/}
                <a key={2} href=""
                   className={this.state.isActive[2] === true ? "list-group-item list-group-item-action active" : "list-group-item list-group-item-action"}
                   id={2} onClick={this.switchLinkToActive}>Custom lemenet</a>
            </div>
        )
    }
}

export default Categories;

in this example i am calling func() inside of the render() method and it leads to something similar to stackoverflow, it just doesn't stop calling it. Anyway to fix that? I didn't really find any solutions to that. If i lets say just do a for loop inside of the render it works as intended it's called only once, so why is the function called endless amount of times

Upvotes: 1

Views: 908

Answers (2)

Panther
Panther

Reputation: 9418

You have to make your ajax calls usually in componentDidMount. It would look something like below

componentDidMount() {
 this.func();
}

In your ajax calls, once you get your response, set it to state. So your func would look something like below

func() {
    let categories = [];
    ajax.request.get('categories').then((resp) => {
        for (let i = 0; i < resp.length; i++) {
            resp[i].isActive = false;
        }
        this.setState({
            data : resp,
        });
    });
}

Your render would use the data in state and render the required DOM structure appropriately.

render() {

    return (
        <div className="list-group col-3">

            {
             (this.state.data || []).map((element, idx) => 
              categories.push(<a key={element.id} href=""
                               className={element.isActive ? "list-group-item list-group-item-action active" : "list-group-item list-group-item-action"}
                               id={idx} onClick={this.switchLinkToActive}>{element.name}</a>);

             })
           }

            <a key={2} href=""
               className={this.state.isActive[2] === true ? "list-group-item list-group-item-action active" : "list-group-item list-group-item-action"}
               id={2} onClick={this.switchLinkToActive}>Custom lemenet</a>
        </div>
    )
}

Upvotes: 0

Sagiv b.g
Sagiv b.g

Reputation: 31024

You should never ever setstate inside render, instead do it in one of the life cycle methods, in your case because you are doing an ajax request you should do that in componentDidMount link

Upvotes: 1

Related Questions