简体   繁体   中英

Can't send request in componentDidMount React Native

I have an issue with sending a request to backend from my componentDidMount(). Basically I need to do two things before rendering screen:

  1. Obtain data from API call and save it to state
  2. Send that obtained data to backend and take response values from backend.

The problem I've faced on first step is that setState() is async, and even though my array is not empty (I see it's elements in render() and componentDidUpdate fucntion) in componentDidMount() when I console.log() array it will be empty. Now, the issue is: I still need to send that state array to backend before showing the screen. But how can I do it, when it appears empty there?

I have everything working fine if I send the request from the Button element in my render function, but that's not exactly what I need. Any suggestions?

        this.state = {
        ActivityItem: [],
        }

componentDidMount() {
    this.getDataFromKit(INTERVAL); //get data from library that does API calls
     this.sendDataToServer(); //sending to backend
 }

componentDidUpdate() {
    console.log("componentDidUpdate ", this.state.ActivityItem) // here array is not empty
}

    getDataFromKit(dateFrom) {
        new Promise((resolve) => {
        AppleKit.getSamples(dateFrom, (err, results) => {
            if (err) {
                return resolve([]);
            }
            const newData = results.map(item => {
                return { ...item, name: "ItemAmount" };
            });

            this.setState({ ActivityItem: [...this.state.ActivityItem, ...newData] })
        })
    });

And last one:

sendDataToServer() { 
    UserService.sendActivityData(this.state.ActivityItem).then(response => {
    }).catch(error => {
        console.log(error.response);
    })

And here it works as expected:

                 <Button
                title='send data!'
                onPress={() => this.sendDataToServer()
                } />

UPDATE If I have like this (wrapped inside initKit function this will return undefined.

 AppleKit.initKit(KitPermissions.uploadBasicKitData(), (err, results) => {
        if (err) {
            return;
        }
        return new Promise((resolve) => {
            AppleKit.getSamples(dateFrom, (err, results) => {
                if (err) return resolve([]);//rest is the same

you have to wait for the promise to resolve. You need something like this:

componentDidMount() {
    this.getDataFromKit(INTERVAL).then(result => {
      this.sendDataToServer(result); //sending to backend
    }).catch(e => console.error);
}

and you can update your other function that fetches data to return it:

getDataFromKit(dateFrom) {
    return new Promise((resolve) => {
        AppleKit.getSamples(dateFrom, (err, results) => {
            if (err) return resolve([]);

            const newData = results.map(item => {
                return { ...item, name: "ItemAmount" };
            });
            const allData = [ ...this.state.ActivityItem, ...newData ];
            this.setState({ ActivityItem: allData });

            resolve(allData);
        });
    });
}

finally, you need the 'sendData' function to not depend on state, but get a param passed to it instead:

sendDataToServer(data) { 
    UserService.sendActivityData(data).then(response => {
      // ... do response stuff
    }).catch(error => {
        console.log(error.response);
    });
}

Handling Multiple Requests

if the requests don't depend on each other:

componentDidMount() {
  Promise.all([
    promise1, 
    promise2, 
    promise3,
  ]).then(([ response1, response2, response3 ]) => {
    // do stuff with your data
  }).catch(e => console.error);
}

if the requests do depend on each other:

componentDidMount() {
  let response1;
  let response2;
  let response3;

  promise1().then(r => {
    response1 = r;
    return promise2(response1);
  }).then(r => {
    response2 = r;
    return promise3(response2);
  }).then(r => {
    response3 = r;

    // do stuff with response1, response2, and response3
  }).catch(e => console.error);
}

as far as your update, it seems like you wrapped your async request in another async request. I'd just chain it instead of wrapping it:

make the initKit a function that returns a promise

function initKit() {
  return new Promise((resolve, reject) => {
    AppleKit.initKit(
      KitPermissions.uploadBasicKitData(), 
      (err, results) => {
        if (err) reject({ error: 'InitKit failed' });
        else resolve({ data: results });
      }
    );
  });
}

make get samples a separate function that returns a promise

function getSamples() {
  return new Promise((resolve) => {
    AppleKit.getSamples(dateFrom, (err, results) => {
      if (err) resolve([]); //rest is the same
      else resolve({ data: results });
    });
  });
}

chain 2 promises back to back: if initKit fails, it will go in the .catch block and getSamples wont run

componentDidMount() {
  initKit().then(kit => {
    return getSamples();
  }).then(samples => {
    // do stuff with samples
  }).catch(e => console.log);
}

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