简体   繁体   中英

Fetch data in ReactJS

There is a get request in componentDidMount()

componentDidMount() {
   var manufacturers = []

   this.props.participants.map(participant => {
     Get("manufacturer/" + participant.id, "").then(result => {
      manufacturers.push(result)
      console.log(manufacturers)
    });
  });

  this.setState({
    participants: manufacturers
  })
}

This console.log(manufacturers) shows that there are objects in the array, but the state of component is empty. How to set it properly after fetching data?

Code of Get() function:

const Config = require('Config')
export async function Get(type, userData) {
    let BaseURL = Config.serverUrl;
    let result = {};
    if(userData)
        result = await fetch(BaseURL+type, {
                method: 'GET',
                headers: new Headers({
                    'Authorization': 'Bearer ' + userData,
                    'Content-Type': 'application/json'
                })
        });
    else
        result = await fetch(BaseURL+type, {
            method: 'GET',
            headers: new Headers({
                'Content-Type': 'application/json'
            })
        });
    let data = await result.json();
    return data;
}

Since you have multiple Get calls to be made and each one is async , you will have to wait until all the result is collected and then set it to the state. You can do it by using Promise.all which can wait for all the Get calls to be resolved first, and then set the data to the state.

I would first create an async function and call it in componentDidMount .

componentDidMount() {
  this.fetchAllData();
}

Then inside this method, wait for all Promises to be resolved and set it to the state once we have the data. you might have to wrap the whole function inside a try..catch block so that if there is any promise rejection due to failure of network call, you can handle it appropriately.

fetchAllData = async () => {
  const manufacturers = await Promise.all(
    this.props.participants.map(participant => 
      Get("manufacturer/" + participant.id, ""))
  )
  this.setState(manufacturers)
};

You need to setState in Get promise callback

componentDidMount() {
   var manufacturers = []

   this.props.participants.map(participant => {
     Get("manufacturer/" + participant.id, "").then(result => {
      manufacturers.push(result)
      console.log(manufacturers)
      this.setState({
        participants: manufacturers
      })
    });
  });
}

You should move your this.setState inside of the .then. Don't exactly know why you're pushing the data to the manufacturers array first. If you use that array for something. If you already have the result in the state you probably won't need the manufacturers array. If not .. You can just set the state with the result like below:

componentDidMount() {
   var manufacturers = []

   this.props.participants.map(participant => {
     Get("manufacturer/" + participant.id, "").then(result => {
      manufacturers.push(result) // Do you need this?
      console.log(manufacturers)
        this.setState({
          participants: result
        })
    });
  });
}

The problem comes from async logic. Using this.setState() outside of the fetch's then() causes the manufacturers property to be empty.

What is complex in your case is that you need to resolve multiple queries in parallel before updating the state. This can be made using the Promise.all() function :

componentDidMount() {
  Promise.all(this.props.participants.map(participant =>
    Get("manufacturer/" + participant.id, "")
  ).then(results => {
    this.setState({
      participants: results // or results.map(result => result.data()) ...
    })
 })
}

Initialize the state before the ComponentDidMount method is called:

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

you should always update State in 'then' or catch block of promise when promise is resolved/rejected...like below

componentDidMount() {
var manufacturers = []

this.props.participants.map(participant => {
 Get("manufacturer/" + participant.id, "").then(result => {
  manufacturers.push(result);

   this.setState({participants: manufacturers});
   console.log(manufacturers);

  });
 });
}

Since your get function returns promise which is async call, when get function executes, it skips to next line of code before resolving to this.setState() in your case, hence not showing updated state. Always remember setState() itself is async and if u need to do any operation after setState , do it in setState() 's callback optional argument like:-

this.setState((currentState)=>{
 // you can access the currentState here
 },()=>{
 //your callback... here you can access directly this.state since it is guranteed 
  //that it will be updated state always
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM