简体   繁体   English

将 API 数据推送到 Chart.js

[英]Pushing API Data into Chart.js

I'm trying to push my API data into my chart, but there seems to be a problem with the timing of when the data is updated versus when the chart is rendered.我试图将我的 API 数据推送到我的图表中,但数据更新时间与图表呈现时间似乎存在问题。 I'm console.logging my two arrays, and it isn't showing anything in the array.我正在控制台记录我的两个 arrays,它没有在数组中显示任何内容。 Does anyone know what I need to change in order for my data to be updated to the state, before the chart renders with that data?有谁知道我需要更改什么才能将我的数据更新到 state,然后再使用该数据呈现图表?

function SmallBox(props) {
    const [chartNums, setChartNums] = useState([])
    const [chartLabels, setChartLabels] = useState([])
    const [chartData, setChartData] = useState({})
    const x = [];
    const y = [];

    const fetchData = async () => {
      await fetch(`https://api.coingecko.com/api/v3/coins/${props.id}/market_chart?vs_currency=usd&days=1`)
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        for (let i = 0; i < data.prices.length; i++){
          x.push(data.prices[i][0])
          setChartLabels(x)
        }

        for (let i = 0; i < data.prices.length; i++){
          y.push(data.prices[i][1])
          setChartNums(y)
        }
        
      })
    };

    const chart = async () => {
        await fetchData()
        console.log(chartNums)
        console.log(chartLabels)
        
        setChartData({
            labels: chartLabels,
            datasets: [
                {
                    label: '$',
                    data: chartNums,
                    backgroundColor: ['rgba(0,0,0,0.09)'],
                    borderColor: `${props.color}`,
                    borderWidth: 4,
                    borderJoinStyle: 'round',
                    borderCapStyle: 'round',
                    borderWidth: 3,
                    pointRadius: 0,
                    pointHitRadius: 10,
                    lineTension: .2,
                }
            ]
        })
    }

    useEffect(() =>{
      chart();
    }, []);

    return (
        <div id={props.id} className="smallBox">
            <div className="smallBox_info">
                <img className="smallBox-icon" src={props.image} alt={props.symbol}/>
                <h2>{props.title}</h2>
            </div>
            
            <div className="smallBox_numbers">
                <h2 className="smallBox-price">$ {props.currentPrice}</h2>
                <h5 className="smallBox-roc">{props.percentChange}</h5>
            </div>
            
            <div className="smallBox_graph">
                <Line data={chartData} options={{
                    responsive: true,
                    maintainAspectRatio: false,
                    title: {text: 'ThickBoyz', display: false},
                    legend: {display: false},
                    layout: {
                        padding: {
                          left: 0,
                          right: 0,
                          top: 0,
                          bottom: 0
                        }
                      },
                      scales: {
                        xAxes: [{
                          display: false,
                          gridLines: {}
                        }],
                        yAxes: [{
                          display: false,
                          gridLines: {}
                        }]
                      },
                      tooltips: {
                        callbacks: {
                          //This removes the tooltip title
                          title: function() {}
                       },
                        //this removes legend color
                        displayColors: false,
                        yPadding: 10,
                        xPadding: 10,
                        position: 'nearest',
                        caretSize: 10,
                        backgroundColor: 'rgba(255,255,255,.9)',
                        bodyFontSize: 15,
                        bodyFontColor: '#303030' 
                      }
                    }}/>  
            </div>
        </div>
    )
}

export default SmallBox

use async- await properly, don't mix promise then method with await.正确使用 async-await,不要将 promise then 方法与 await 混合使用。

import React, { useEffect, useState, useCallback } from "react";
import { Line } from "react-chartjs-2";
import "./styles.css";

export default function App() {
  const [chartNums, setChartNums] = useState([]);
  const [chartLabels, setChartLabels] = useState([]);
  const [chartData, setChartData] = useState({});
  const x = [];
  const y = [];
  const props = {
    id: "bitcoin"
  };

  const fetchData = useCallback(async () => {
    const response = await fetch(
      `https://api.coingecko.com/api/v3/coins/${props.id}/market_chart?vs_currency=usd&days=1`
    );
    const data = await response.json();
    if (data && data.prices) {
      console.log(data.prices);
      for (let i = 0; i < data.prices.length; i++) {
        x.push(data.prices[i][0]);
        setChartLabels(x);
      }

      for (let i = 0; i < data.prices.length; i++) {
        y.push(data.prices[i][1]);
        setChartNums(y);
      }
    }
  }, [props]);

  const chart = useCallback(async () => {
    await fetchData();
    console.log(chartNums);
    console.log(chartLabels);

    setChartData({
      labels: chartLabels,
      datasets: [
        {
          label: "$",
          data: chartNums,
          backgroundColor: ["rgba(0,0,0,0.09)"],
          borderColor: `${props.color}`,
          borderWidth: 4,
          borderJoinStyle: "round",
          borderCapStyle: "round",
          pointRadius: 0,
          pointHitRadius: 10,
          lineTension: 0.2
        }
      ]
    });
  }, [chartNums, chartLabels, fetchData, props.color]);

  useEffect(() => {
    chart();
  }, [chart]);

  return (
    <div id={props.id} className="smallBox">
      <div className="smallBox_info">
        <img className="smallBox-icon" src={props.image} alt={props.symbol} />
        <h2>{props.title}</h2>
      </div>

      <div className="smallBox_numbers">
        <h2 className="smallBox-price">$ {props.currentPrice}</h2>
        <h5 className="smallBox-roc">{props.percentChange}</h5>
      </div>

      <div className="smallBox_graph">
        <Line
          data={chartData}
          options={{
            responsive: true,
            maintainAspectRatio: false,
            title: { text: "ThickBoyz", display: false },
            legend: { display: false },
            layout: {
              padding: {
                left: 0,
                right: 0,
                top: 0,
                bottom: 0
              }
            },
            scales: {
              xAxes: [
                {
                  display: false,
                  gridLines: {}
                }
              ],
              yAxes: [
                {
                  display: false,
                  gridLines: {}
                }
              ]
            },
            tooltips: {
              callbacks: {
                //This removes the tooltip title
                title: function () {}
              },
              //this removes legend color
              displayColors: false,
              yPadding: 10,
              xPadding: 10,
              position: "nearest",
              caretSize: 10,
              backgroundColor: "rgba(255,255,255,.9)",
              bodyFontSize: 15,
              bodyFontColor: "#303030"
            }
          }}
        />
      </div>
    </div>
  );
}

Sandbox link - https://codesandbox.io/s/chartjs-fetchapidata-r3ghc?file=/src/App.js沙盒链接 - https://codesandbox.io/s/chartjs-fetchapidata-r3ghc?file=/src/App.js

Consider sticking to either .then() syntax or async/await .考虑坚持使用.then()语法或async/await I would recommend using the latter, which should make things more straightforward:我建议使用后者,这应该使事情更简单:

 const fetchData = async () => {
      const response = await fetch(`https://api.coingecko.com/api/v3/coins/1/market_chart?vs_currency=usd&days=1`)
      const data = await response.json()
      data.prices.forEach(price => {
        x.push(price[0])
        setChartLabels(x)
        
        y.push(price[1])
        setChartNums(y)
    });
}

Next, consider whether you actually need to store chartLabels and chartNums in React state - they aren't used in your JSX, so returning them as plain old variables is probably clearer:接下来,考虑您是否真的需要将chartLabelschartNums存储在 React state 中——它们没有在您的 JSX 中使用,因此将它们作为普通的旧变量返回可能更清楚:

 const fetchData = async () => {
      const response = await fetch(`https://api.coingecko.com/api/v3/coins/1/market_chart?vs_currency=usd&days=1`)
      const data = await response.json()
      chartLabels = data.prices.map(price => price[0])
      chartNums = data.prices.map(price => price[1]
      return [chartLabels,chartNums]
}

then later,然后后来,

const [chartLabels, chartNums] = await fetchData()
  const [chartLabels, setChartLabels] = useState([]);
  const [chartData, setChartData] = useState({});
  const x = [];
  const y = [];
  const props = {
    id: "bitcoin"
  };

  const fetchData = useCallback(async () => {
    const response = await fetch(
      `https://api.coingecko.com/api/v3/coins/${props.id}/market_chart?vs_currency=usd&days=1`
    );
    const data = await response.json();
    if (data && data.prices) {
      console.log(data.prices);
      for (let i = 0; i < data.prices.length; i++) {
        x.push(data.prices[i][0]);
        setChartLabels(x);
      }

      for (let i = 0; i < data.prices.length; i++) {
        y.push(data.prices[i][1]);
        setChartNums(y);
      }
    }
  }, [props,x,y]);

Referring to the solution provided above you can init the x and y arrays wrapping useMemo Hook to return and more optimal solution and prevent Warnings like this参考上面提供的解决方案,您可以初始化 x 和 y arrays 包装 useMemo Hook 以返回更优化的解决方案并防止这样的警告

Pro tip: if you add the dependencies incorrectly or none at all repetitive API calls might get you block.专业提示:如果您不正确地添加依赖项或根本没有添加依赖项,重复的 API 调用可能会让您被阻止。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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