Question about asynchronous data

I have a React Component called Recipe. It reads in the Recipe ID with this.props.match.id and puts it into state. I have a function called useRecipe, which I want activated onClick and will eventually do some database stuff. However, I keep getting an error I think because of the asynchronous nature of the API call. It reads my first variable as undefined because state hasn’t been populated yet. I was wondering if there was a fix to this. The component is below:

import React from "react";

import axios from "axios";

class Recipe extends React.Component {

    // console.log(grep)

    state = {

        data: []

    }

    handleUseRecipe = () => {

        let strIngredients = this.state.data.Ingredients;

        console.log(strIngredients)

        let arIngredients = strIngredients.split(", ");

        let strAmounts = this.state.data.Amounts;

        let arAmounts = strAmounts.split(", ");

        let strUnits = this.state.data.Units;

        let arUnits = strUnits.split(", ");

        console.log(arIngredients);

        console.log(arAmounts);

        console.log(arUnits);

        // For Each

    }

    componentDidMount(){

        const id = this.props.match.params.id

        axios.get(`http://localhost:4000/recipe/${id}`)

        .then(res => {

      this.setState({

        data: res.data

      } )

          })

    }

render(){

    console.log(this.state.data.Ingredients)

return (

    <div>

      <span>{JSON.stringify(this.state.data)}</span>

      <button 

      onClick={this.handleUseRecipe()}

      >Use Recipe</button>

    </div>

   

)

}

    }

export default Recipe;

And here is the error. Let me know if anyone can help! I will be here.

When you use parens the method is called on initial render. Remove parens and it should work.

To expand on that, it’s not called an initial render. In JavaScript, you call a function using parentheses, and it resolves to a value. So

function one() { return 1; }

Say you have that function. one() and 1 are exactly the same thing, calling the function one resolves to the number 1 so the two things are identical.

Functions like event handlers (onClick), or like array.map(someFunction) take a callback function, not a value

onClick={this.handleUseRecipe()}

Is a value, and that value will be undefined, as the function doesn’t return anything. So you’ve written

onClick={undefined}

onClick, and all other event handlers, take a function, not the value returned from a function


Also, you haven’t handled the time it takes to get the data (the data is not asynchronous btw, it’s the function call that’s async). The fetch in componentDidMount has initiated that request, but you have no guarantee that it’s completed by the time stuff renders to screen.

So you generally just say, in the render, that if there is no data, render null, otherwise render normally.

Finally, you’ve said data is an array, then you’re trying to access properties on it (data.Ingredients). It won’t break things it it’s an object rather than an array, it’s just confusing.

Thanks guys! Changing the syntax for the onClick event fixed the problem. I will note your other suggestions as well.

1 Like