1

I am trying to use axios to get data from the api (https://reqres.in/) and display in my react app. Before this I fetched the data from the API using fetch method in javascript. Now I have tried coding this from various resources. How should I do it. Is it the correct method?

My app.js file-

import React, { Component } from 'react';
import './App.css'; 
import axios from 'axios';

class App extends Component {
  constructor(props) {
    super(props);
  this.successShow = this.successShow.bind(this);
  this.errorShow = this.errorShow.bind(this);
}
componentDidMount() {
 axios.get('https://reqres.in/api/products/3')
   .then(function (response) {
     this.successShow(response);
   })
   .catch(function (error) {
     this.errorShow(error);
   });
 }
successShow(response) {
 this.member = <pre>{JSON.stringify(response.data, null, '\t')}</pre> ;
}
errorShow(error) {
 this.member = <pre>{JSON.stringify(error.response.data, null, '\t')}</pre>;
}
render() {
  return (
    <div>
      <h2>Welcome to React</h2>
      <h3>{JSON.stringify(this.state.person.data)}</h3>
      <div>{this.member}</div>
    </div>
  );
  }
 }
export default App;

It also gives the error - Unhandled Rejection (TypeError): Cannot read property 'errorShow' of undefined.

2
  • Possible duplicate of TypeError: Cannot read property 'setState' of undefined Commented Aug 23, 2017 at 11:05
  • One of the key things about arrow functions is that they don't create their own new scope, they remain in the current scope Commented Mar 14, 2019 at 9:26

4 Answers 4

3

Changes:

1. You need to bind this with then and catch callback methods, use arrow functions.

2. You didn't define the initial state and using this.state.person.data it will throw error.

3. Storing the UI in state or global variable is not a good idea, ui part should be inside render method only.

Write it like this:

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            person: {}
        }
        //this.successShow = this.successShow.bind(this);
        //this.errorShow = this.errorShow.bind(this);
    }

    componentDidMount() {
        axios.get('https://reqres.in/api/products/3')
        .then((response) => {
            this.successShow(response);
        })
        .catch((error) => {
            this.successShow(error);
        });
    }

    successShow(response) {
        this.setState({
            person: response.data
        });
    }

    render() {
        return (
            <div>
              <h2>Welcome to React</h2>
              <h3>{JSON.stringify(this.state.person.data)}</h3>

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

              <div>{this.member}</div>
            </div>
        );
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Hey Thanks for the answer,it works. But I didn't understand your first point.
2

When you call this.errorShow() inside of the function, this is not your component object, but context of function. You should use arrow functions instead, arrow functions do not create its own this so you can access your component this:

componentDidMount() {
 axios.get('https://reqres.in/api/products/3')
   .then((response) => {
     this.successShow(response);
   })
   .catch(error) => {
     this.errorShow(error);
   });
 }

More info about arrow functions

Comments

1

Try this:

componentDidMount() {
 axios.get('https://reqres.in/api/products/3')
   .then((response) => {
     this.successShow(response);
   })
   .catch((error) => {
     this.errorShow(error);
   });
 }

Use arrow functions to remain the right scope of this

Comments

1

The problem is that the this in your then and catch callbacks doesn't refer to your class, but to the default (global) scope. You need to bind the right this. You actually already have the appropriate functions set up with this binding, so you can just use them directly:

componentDidMount() {
  axios.get('https://reqres.in/api/products/3')
   .then(this.successShow)
   .catch(this.errorShow);
}

In general, you can also use => function syntax, which inherits the 'this' from the scope the function is declared in, rather than using the global scope. E.g.

componentDidMount() {
  axios.get('https://reqres.in/api/products/3')
   .then(success => this.successShow(success))
   .catch(error => this.errorShow(error));
}

(note the => functions are completely unnecessary here of course).

You have an additional problem, which is the you need to store member in component state (this.state.member), not just as a field, and use the setState function to update it. Otherwise your component won't re-render when you update member.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.