【问题标题】:Can't send request in componentDidMount React Native无法在 componentDidMount React Native 中发送请求
【发布时间】:2024-01-19 13:41:01
【问题描述】:

我在从我的 componentDidMount() 向后端发送请求时遇到问题。基本上在渲染屏幕之前我需要做两件事:

  1. 从API调用中获取数据并保存到状态
  2. 将获取的数据发送到后端并从后端获取响应值。

我在第一步遇到的问题是 setState() 是异步的,即使我在 console.log 中的 componentDidMount() 中的数组不是空的(我看到它是 render() 和 componentDidUpdate 函数中的元素) () 数组它将为空。现在,问题是:在显示屏幕之前,我仍然需要将该状态数组发送到后端。但是,当它在那里显示为空时,我该怎么做呢?

如果我从渲染函数中的 Button 元素发送请求,一切正常,但这并不是我所需要的。有什么建议吗?

        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] })
        })
    });

最后一个:

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

在这里它按预期工作:

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

更新 如果我喜欢这个(包裹在 initKit 函数中,这将返回 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

【问题讨论】:

    标签: javascript reactjs react-native state


    【解决方案1】:

    您必须等待承诺解决。你需要这样的东西:

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

    您可以更新获取数据以返回数据的其他函数:

    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);
            });
        });
    }
    

    最后,您需要“sendData”函数不依赖于状态,而是获取传递给它的参数:

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

    处理多个请求

    如果请求不相互依赖:

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

    如果请求确实相互依赖:

    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);
    }
    

    就您的更新而言,您似乎将异步请求包装在另一个异步请求中。我只是链它而不是包装它:

    使 initKit 成为一个返回承诺的函数

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

    让 get samples 成为一个单独的函数,返回一个 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 承诺背靠背:如果 initKit 失败,它将进入.catch 块并且getSamples 不会运行

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

    【讨论】:

    • 感谢您的帮助,我想我现在知道它应该如何工作了。但还有一点:如果我有几个 APi 请求并因此返回几个 Promise,你会建议如何处理?
    • 感谢您的帮助,您的方法效果很好。最后一件事,如果我将它们放在另一个块中,我该如何返回它们? (我会更新问题)