如何在 React 返回 promise 后才绘制图表?

How do I draw chart only after promise is returned in React?

我正在为 Chartjs 使用 React 包装器。我使用 fetch API 调用 Nomics API 来获取数据并将其存储在一些 arrays 中。然后我想在新的 Chartjs 实例中使用数组。除了我的图表呈现外,一切正常,我认为这是因为它在承诺完成之前呈现。在对 Nomics API 的调用完成之前,我如何只 return 图表或在完成后更新它?

这是我的组件:

import React from 'react';
import {Line} from 'react-chartjs-2';

const Day = () =>{
    
    //starting price reiterated over the length of the data.
    const zeroLine = [];
    //stores all the increments of time
    const timeLabels = [];
    //List of all of the prices
    const prices = [];
    
    
    
    fetch("https://api.nomics.com/v1/currencies/sparkline?key=yadayadayada&ids=BTC&start=2020-04-14T00%3A00%3A00Z&end=2020-04-20T01%3A00%3A00Z",
    {}).then((res) => res.json())
      .then((result) => {
        
        for(var i = 0; i <= result[0].prices.length - 1; i++){
            zeroLine.push(result[0].prices[0]);
            timeLabels.push(result[0].timestamps[i]);
            prices.push(result[0].prices[i]);
            
        }
      });
    
    const chartData = {
      labels: timeLabels,
      datasets: [
        {
          label: 'Price',
          fill: false,
          lineTension: 0,
          backgroundColor: 'rgba(75,192,192,1)',
          borderColor: 'rgba(0,0,0,1)',
          borderWidth: 2,
          data: prices
        },
        {
          //Change this to create points for every time/date
          label: '0 line',
          fill: false,
          borderDash: [10,5],
          data: zeroLine,
          
          
        }
      ]
    }

    return(
    <Line
          data={chartData}
          options={{
            elements:{
                point: {
                    radius: 0
                }
            },
            title:{
              display:true,
              text:'BTC Price',
              fontSize:20
            },
            legend:{
              display:false,
              position:'right'
            }
          }}
        />
    )
}

export default Day;

您可以使用 useStateuseEffect 挂钩来实现此目的。

useEffect 挂钩可以充当 componentDidMount(当您将依赖数组作为 [] 传递时)、componentDidUpdate(当您将值传递到依赖数组时)和 componentWillUnmount(当您有第三个函数时)

另一方面,useState 类似于使用 setState。它会在组件发生变化时触发组件 re-render。

在你的情况下,我们现在所做的基本上是更新获取响应的状态,这会触发重新渲染

import React, {useState, useEffect} from 'react';
import {Line} from 'react-chartjs-2';

const Day = () =>{
    const [zeroLine, setZeroLine] = useState([]);
    const [timeLabels, setTimeLabels] = useState([]);
    const [prices, setPrices] = useState([]);
    
    useEffect(() => {
      fetch("https://api.nomics.com/v1/currencies/sparkline?key=yadayadayada&ids=BTC&start=2020-04-14T00%3A00%3A00Z&end=2020-04-20T01%3A00%3A00Z",
    {}).then((res) => res.json())
      .then((result) => {
        const zL = [];
        const tL = [];
        const p = [];
        for(var i = 0; i <= result[0].prices.length - 1; i++){
            zL.push(result[0].prices[0]);
            tL.push(result[0].timestamps[i]);
            p.push(result[0].prices[i]);
        }
        setZeroLine(zL);
        setTimeLabels(tL);
        setPrices(p);
      });
    }, []);
    
    const chartData = {
      labels: timeLabels,
      datasets: [
        {
          label: 'Price',
          fill: false,
          lineTension: 0,
          backgroundColor: 'rgba(75,192,192,1)',
          borderColor: 'rgba(0,0,0,1)',
          borderWidth: 2,
          data: prices
        },
        {
          //Change this to create points for every time/date
          label: '0 line',
          fill: false,
          borderDash: [10,5],
          data: zeroLine,
          
          
        }
      ]
    }

    return(
      <Line
          data={chartData}
          options={{
            elements:{
                point: {
                    radius: 0
                }
            },
            title:{
              display:true,
              text:'BTC Price',
              fontSize:20
            },
            legend:{
              display:false,
              position:'right'
            }
          }}
        />
    )
}

export default Day;

您可以使用 useStateuseEffect 挂钩和条件渲染来做到这一点:

import React, {useState, useEffect} from 'react';
import {Line} from 'react-chartjs-2';

const Day = () =>{
    // this piece of state will hold the data passed to the chart component once it returns from your fetch call.
    const [chartData, setChartData] = useState(null);
    
    
    const getChartData = () => fetch("https://api.nomics.com/v1/currencies/sparkline?key=yadayadayada&ids=BTC&start=2020-04-14T00%3A00%3A00Z&end=2020-04-20T01%3A00%3A00Z",
    {}).then((res) => res.json())
      .then((result) => {
            
        //starting price reiterated over the length of the data.
        const zeroLine = [];
        //stores all the increments of time
        const timeLabels = [];
        //List of all of the prices
        const prices = [];
        for(var i = 0; i <= result[0].prices.length - 1; i++){
            zeroLine.push(result[0].prices[0]);
            timeLabels.push(result[0].timestamps[i]);
            prices.push(result[0].prices[i]);
            
        }
        const chartData = {
          labels: timeLabels,
          datasets: [
            {
              label: 'Price',
              fill: false,
              lineTension: 0,
              backgroundColor: 'rgba(75,192,192,1)',
              borderColor: 'rgba(0,0,0,1)',
              borderWidth: 2,
              data: prices
            },
            {
              //Change this to create points for every time/date
              label: '0 line',
              fill: false,
              borderDash: [10,5],
              data: zeroLine,
          
          
            }
          ]
        }
        setChartData(chartData)
      });

    useEffect(getChartData, [])

    return chartData ? (
    <Line
          data={chartData}
          options={{
            elements:{
                point: {
                    radius: 0
                }
            },
            title:{
              display:true,
              text:'BTC Price',
              fontSize:20
            },
            legend:{
              display:false,
              position:'right'
            }
          }}
        />
    ) : <p>loading...</p>
}

export default Day;