Mok
Mok

Reputation: 41

reactjs how come my render keeps getting invoked a lot?

Hello I have have the following component

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import RecipeItems from './RecipeItems';

class RecipeContainer extends Component {
    constructor() {
        super();
        this.state = {

        };
    }
    loadRecipe()
    {
        fetch("http://localhost:64755/Api/recipe/" + this.props.recipeId)
        .then(result => {
            return result.json();
        })
        .then(data => {

            //const foo = data;
            this.setState({ Recipe: data })
        }
        )            
        .catch(e => {
            console.log(e)
            return e;
        });
    }
    render() {
        this.loadRecipe()

            console.log('in recipecontainer');
            return(<div></div>)
    }
}

RecipeContainer.propTypes = {
    recipeId: PropTypes.number
};

export default RecipeContainer;

I originally put a console.log() for debugging but then I noticed this method is being call in what it seems is a loop. It doesn't stop. What is wrong here? I know when I remove this.setState({ Recipe: data }) then the loop stops.

Upvotes: 0

Views: 215

Answers (3)

hannad rehman
hannad rehman

Reputation: 4331

its a loop. render method will be called whenever there is a change in props or state. in your case you are calling the loadRecipe(). which updates the state. causes re execution of render, again calls loadRecipe() . so this will an endless loop. insted you can call the loadRecipe in some lifecycle method. say componentDidMount().

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import RecipeItems from './RecipeItems';

class RecipeContainer extends Component {
constructor() {
    super();
    this.state = {

    };
}
componentDidMount(){
  this.loadRecipe() // will be called only once. 
  // thus the state will be updated once by this function.

}
loadRecipe()
{
    fetch("http://localhost:64755/Api/recipe/" + this.props.recipeId)
    .then(result => {
        return result.json();
    })
    .then(data => {

        //const foo = data;
        this.setState({ Recipe: data })
    }
    )            
    .catch(e => {
        console.log(e)
        return e;
    });
}
render() {


        console.log('in recipecontainer');
        return(<div></div>)
       }
   }

RecipeContainer.propTypes = {
    recipeId: PropTypes.number
};

export default RecipeContainer;

Upvotes: 0

Shivam
Shivam

Reputation: 2248

You shouldnt run anything apart from rendering html code in your render function. So move the this.loadRecipe to your componentDidMount function and see if that helps.

also here is the right syntax for your ajax call:

fetch("http://localhost:64755/Api/recipe/" + this.props.recipeId)
    .then(result => {
        this.setState({ Recipe: result.json() })
    })           
    .catch(e => {
        console.log(e);
    });

also you can set defultProps within your class, like so:

class RecipeContainer extends Component {
    static defaultProps = {
       ...defaultprops
    }

    constructor() {
        super();
        this.state = {

        };
    }
}

Upvotes: 0

palsrealm
palsrealm

Reputation: 5243

You are making a fetch call in your render method. This call updates the state of the component using this.setstate, which triggers a call to render and so on. This is why you see the console.log statement in a loop.

You should fetch data in componentDidMount lifecycle method to prevent this type of infinite loop. componentDidMount will be called only after render finishes running the first time and there is no chance of the infinite loop of calls.

From the docs:

componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.

Code:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import RecipeItems from './RecipeItems';

class RecipeContainer extends Component {
    constructor() {
        super();
        this.state = {
            Recipe: null
        };
    }

    componentDidMount(){
        fetch("http://localhost:64755/Api/recipe/" + this.props.recipeId)
        .then(result => {
            return result.json();
        })
        .then(data => {
            this.setState({ Recipe: data });
        })                    
        .catch(e => {
            console.log(e);
            return e;
        });
    }
    render() {    
            console.log('in recipecontainer');
            return(<div></div>);
    }
}

RecipeContainer.propTypes = {
    recipeId: PropTypes.number
};

export default RecipeContainer;

Upvotes: 1

Related Questions