Axios not updating state from API in function called on Click, but works on identical function on Component Mount in React

Viewed 262

I'm working on a basic API pull within a basic React component using Axios. When my component mounts I pull an API that is a random Chuck Norris quote and it works perfectly. However, when I try to make a new pull and update state in an identical function that is called onClick, I get an error message saying "Unhandled Rejection (TypeError): Cannot read property 'setState' of undefined."

However, when I console.log the values from API pull, they give me the expected result, so I don't understand why I can console.log a value, get a string, and then have React tell me that string is undefined.

I've looked at several stackoverflow threads, and the answers I'm seeing look about identical to my current non-working solution. Any insights would be very appreciated.

import React, {Component} from 'react'
import axios from 'axios'


class App extends Component {
  state = {
    quote: ''
  }

  componentDidMount(){
    axios.get('https://api.chucknorris.io/jokes/random')
      .then(res => {
        console.log('response', res.data.value)
        this.setState({
          quote: res.data.value
        })
      })
  }

  getNewFact(){
    axios.get('https://api.chucknorris.io/jokes/random')
      .then(res => {
        console.log('response', res.data.value)
        this.setState({
        quote: res.value
      })
    })
  }

  render () {
    return(
      <div>
      <h1>Chuck Norris Facts</h1>
      <p>{this.state.quote}</p>
    <button onClick={this.getNewFact}>get new fact</button>
    </div>
    )
  }
}

export default App
3 Answers

You have to use arrow function instead of a normal, because that this is not pointing directly to the class. So instead of:

getNewFact(){
axios.get('https://api.chucknorris.io/jokes/random')
  .then(res => {
    console.log('response', res.data.value)
    this.setState({
    quote: res.value
  })
})

}

Will be:

getNewFact = () => {
axios.get('https://api.chucknorris.io/jokes/random')
  .then(res => {
    console.log('response', res.data.value)
    this.setState({
    quote: res.data.value // also fix this or nothing will show after clicking the button
  })
})

}

import React, {Component} from 'react'
import axios from 'axios'

class App extends Component {

  state = {
    fact:''
  }

  handleonClick = () => {
    axios.get('https://api.chucknorris.io/jokes/random')
    .then(res => {

      console.log(res.data.value)
      this.setState({

        fact: res.data.value
      })
    })
  }
  
  componentDidMount(){
    axios.get('https://api.chucknorris.io/jokes/random')
    .then(res => {

      console.log(res.data.value)
      this.setState({

        fact: res.data.value
      })
    })
  }

  render(){
    return(
      <div>
        <h1 class='title'>Chuck Noris facts</h1>
        <p>{this.state.fact}</p>
        <br/>
        <button className='fact-btn' onClick={this.handleonClick}>New Fact</button>
      </div>
    )
  }
}

export default App;

Try

<button onClick={() => this.getNewFact()}>get new fact</button>

Also in your componentDidMount call you are setting the quote value to

quote: res.data.value

Then in the getNewFact function you are setting it to

quote: res.value
Related