Paulos3000
Paulos3000

Reputation: 3545

How to handle fetch API AJAX response in React

I am making a simple AJAX request with the fetch API in React, specifically in the componentDidMount() function.

It is working, because the console appears to be logging the result. However, I don't know how to access the response...

componentDidMount = () => {

      let URL = 'https://jsonplaceholder.typicode.com/users'

         fetch(URL)
         .then(function(response) {
            let myData = response.json()
            return myData;
         })
         .then(function(json) {
            console.log('parsed json', json)
         })
         .catch(function(ex) {
            console.log('parsing failed', ex)
         })

   } // end componentDidMount

I tried accessing myData outside of the fetch method, but this throws an error saying that it is undefined. So it is only accessible within the scope of the function.

I then tried this:

     .then(function(response) {
        let myData = response.json()
        // return myData;
        this.setState({
           data: myData
        })
     })

This time, I get Cannot read property 'setState' of undefined(…)

How do I pass the fetch response to the state, or even just a global variable?


UPDATE

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

class App extends Component {

   constructor(props) {
      super(props);
      this.state = {
         data: null
      }
   }

   componentDidMount() {
      let URL = 'https://jsonplaceholder.typicode.com/users'  
         fetch(URL)
         .then( (response) => {
            let myData = response.json()
            // return myData;
            this.setState({
               data: myData
            })
         })
         .then( (json) => {
            console.log('parsed json', json)
         })
         .catch( (ex) => {
            console.log('parsing failed', ex)
         })
         console.log(this.state.data)
   } // end componentDidMount

  render() {
    return (
      <div className="App">
         {this.state.data}
      </div>
    );
  }
}

export default App;

Upvotes: 6

Views: 19557

Answers (6)

Ye Yint
Ye Yint

Reputation: 924

Change the way you access the response data by using '=>' instead of function to be in the same context.

componentDidMount = () => {

      let URL = 'https://jsonplaceholder.typicode.com/users'

         fetch(URL)
         .then(function(response) {
            let myData = response.json()
            return myData;
         })
         .then((json) => {
            console.log('parsed json', json)
         })
         .catch(function(ex) {
            console.log('parsing failed', ex)
         })

} // end componentDidMount

Upvotes: 1

Brijmohan Karadia
Brijmohan Karadia

Reputation: 447

REACT NATIVE

import React, { Component } from 'react';

import {
AppRegistry,
StyleSheet,
Text,
View,
} from 'react-native';

export default class SampleApp extends Component {
constructor(props) {
super(props);
this.state = {
    data:  'Request '
    }
}

componentDidMount = () => {
fetch('http://localhost/replymsg.json', {
                      mode: "no-cors",
                      method: "GET",
                      headers: {
                        "Accept": "application/json"
                      },} )
                      .then(response => {
                      if (response.ok) {

                          response.json().then(json => {

                            console.warn( JSON.stringify(json.msg ));
                              this.setState({
                                 data: JSON.stringify(json)
                            })

                        });
                      }
                    }); 

}



render() { 
return (
    <Text>  {this.state.data}</Text>
    );
    }
}

AppRegistry.registerComponent('SampleApp', () => SampleApp);

JSON FILE create a file replymsg.json and put below content and it should host to local host like : http://localhost/replymsg.json

{"status":"200ok","CurrentID":28,"msg":"msg successfully reply"}

Upvotes: 1

Floyd
Floyd

Reputation: 367

You need to bind current context to the target function

fetch(URL)
         .then(function(response) {
            return response.json();
         })
         .then(function(json) {
            this.setState({data: json})
         }.bind(this))
         .catch(function(ex) {
            console.log('parsing failed', ex)
         })

Upvotes: 0

Patrick Grimard
Patrick Grimard

Reputation: 7126

You're on the right track with this.setState however this is no longer in the context of the component when you call it within the function handling the response. Using a => function maintains the context of this.

fetch(URL)
    .then((res) => res.json())
    .then((json) => this.setState({data: json}));

Upvotes: 3

StackOverMySoul
StackOverMySoul

Reputation: 2037

You have two issues as far as I can see, response.json() returns a promise, so you don't wanna set myData to the promise, instead first resolve the promise and then you can access your data.

Second, this is not in the same scope inside your fetch request, so that's why you are getting undefined, you can try saving the scope of this outside fetch:

var component = this;

fetch(URL)
 .then( (response) => {
    return response.json()    
 })
 .then( (json) => {
    component.setState({
       data: json
    })
    console.log('parsed json', json)
 })
 .catch( (ex) => {
    console.log('parsing failed', ex)
 })
 console.log(this.state.data)

Upvotes: 13

Tomasz Nowak
Tomasz Nowak

Reputation: 186

setState is undefined, because you use classic function syntax instead arrow function. Arrow function takes 'this' keyword from 'parent' function, a classic function() {} creates it's own 'this' keyword. Try this

.then(response => {
    let myData = response.json()
    // return myData;
    this.setState({
       data: myData
    })
 })

Upvotes: 7

Related Questions