【问题标题】:How to finish Fetch data completely and assign it to component state before proceeding further in componentDidMount React?如何在 componentDidMount React 进一步进行之前完成 Fetch 数据并将其分配给组件状态?
【发布时间】:2019-01-08 18:14:59
【问题描述】:

我必须执行多个提取查询。根据我的第一个查询,我在收到所有我应该能够将数据分配给反应组件状态后进行多个其他查询。看来我在 fetch 方法完成之前将值分配给组件状态,因此它们显示为空数组。

我已经尝试移除外部的内部 fetch 方法并执行查询。

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

class App extends Component {
  constructor (props) {
      super (props);
      this.state = {
        status: 'disconnected',
        devices: [],
        dataPoints: []
      };
  }

  componentDidMount() {
    // Get Zigbee devices
    fetch('http://localhost:3000/ssapi/zb/dev')
    .then((res) => res.json())
    .then((data) => {

      this.setState({
        devices : data
       })
      data.map((device) => {
        const dataPoint = []
        JSON.parse(device.metadata).dataGroups.map((datagroup) =>{
          const url = 'http://localhost:3000/ssapi/zb/dev/' + device.id + '/ldev/' +  datagroup.ldevKey + '/data/' + datagroup.dpKey;
          fetch(url)
          .then((res) => res.json())
          .then((data) =>{
            dataPoint.concat(data)
            console.log('Data', data);
            console.log('Inside dataPoint', dataPoint);
          })
          .catch((error) => console.log(error));
        }) // dataGroups.map
        console.log("Final dataPoint", dataPoint);
        const dataPoints = this.state.dataPoints.concat(dataPoint);
        this.setState({ dataPoints });
      }) // data.map

    }) // fetch
    .catch((error) => console.log(error));
  }

  render() {
    console.log('Render Devices', this.state.devices);
    console.log('Render dataPoints', this.state.dataPoints);
  }][1]][1]

我期待最终的组件状态看起来像这样 或在渲染功能中 - 控制台日志记录应如下所示。

devices = [{},{},{},{},{}...]
dataPoints = [[{},{},{},..], [{},{},{},..], [{},{},{},..], ....]

【问题讨论】:

    标签: javascript reactjs fetch


    【解决方案1】:

    一个常见的 React 模式是在你的状态中设置一个加载标志,并在页面未加载时显示一个加载器(或返回 null)。

    构造函数:

    class App extends Component {
      constructor (props) {
        super (props);
        this.state = {
          status: 'disconnected',
          devices: [],
          dataPoints: [],
          loading: true
        };
      }
    }
    

    在您的 componentDidMount 中:(简化)

    componentDidMount() {
      fetch('http://localhost:3000/ssapi/zb/dev')
      .then((res) =>
        this.setState({data: res.json(), loading: false});
      )
    }
    

    在你的渲染函数中

    render() {
      if (this.state.loading) {
        return <div>Loading ... Please Wait.</div>;
      }
    
      // Here render when data is available
    }
    

    重要提示:

    在您的 componentDidMount 函数中,您正在执行 2 setState。你应该只做一个来防止不必要的重新渲染。

    在您的示例中,删除第一个

      this.setState({
         devices : data
      })
    

    并在最后合并两者而不是this.setState({ dataPoints, devices: data });

    【讨论】:

      【解决方案2】:

      我的原因是在dataPoint.concat(data),array.concat 返回一个新数组,它是一个不可变的函数。要解决这个问题,请尝试:dataPoint = dataPoint.concat(data)

      【讨论】:

        【解决方案3】:

        map 中的代码const dataPoints = this.state.dataPoints.concat(dataPoint) 将始终连接空数组,因为 fetch 是异步的,而您的 dataPoint 只会在 api 调用后获得值。

        其他问题是dataPoint.concat(data) concat 返回一个新数组,但您没有存储可以使用dataPoint = dataPoint.concat(data)dataPoint = [...dataPoint, ...data] 的新数组

        你需要在const dataPoints = this.state.dataPoints.concat(dataPoint)之前等待api调用的结果。你可以使用 Promise.all

        import React, { Component } from 'react';
        import './App.css';
        import Sensors from './iot/Sensors';
        
        class App extends Component {
            constructor (props) {
            super (props);
            this.state = {
                status: 'disconnected',
                devices: [],
                dataPoints: []
            };
        }
        
        componentDidMount() {
            // Get Zigbee devices
            fetch('http://localhost:3000/ssapi/zb/dev')
            .then((res) => res.json())
            .then((data) => {
                this.setState({
                    devices : data
                })
                //Using forEach instead of map because we don't need the return of map
                data.forEach((device) => {
                    const urls = JSON.parse(device.metadata).dataGroups.map((datagroup) =>
                        'http://localhost:3000/ssapi/zb/dev/' + device.id + '/ldev/' +  datagroup.ldevKey + '/data/' + datagroup.dpKey) // dataGroups.map
                    Promise.all(urls.map(fetch))
                    .then(responses => 
                        Promise.all(responses.map(res => res.json()))
                    )
                    .then((data) =>{
                        //This data will be array of responses of all fetch fired
                        //destructuring response in array
                        const dataPoint = data.reduce((acc, curr)=> acc.concat(curr),[]) 
                        const dataPoints = this.state.dataPoints.concat(dataPoint)              
                        console.log('All Data', data);
                        console.log('Inside dataPoint', dataPoint);
                        this.setState({ dataPoints });
                    })
                    .catch((error) => console.log(error));
                }) // data.map
            }) // fetch
            .catch((error) => console.log(error));
        }
        
        render() {
            console.log('Render Devices', this.state.devices);
            console.log('Render dataPoints', this.state.dataPoints);
        }
        

        【讨论】:

          猜你喜欢
          • 2022-01-05
          • 2019-07-16
          • 1970-01-01
          • 2022-07-11
          • 2018-01-08
          • 1970-01-01
          • 2020-12-21
          • 1970-01-01
          • 2015-03-31
          相关资源
          最近更新 更多