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. I'm console.logging my two arrays, and it isn't showing anything in the array. 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?
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.
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
Consider sticking to either .then()
syntax or 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:
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
Pro tip: if you add the dependencies incorrectly or none at all repetitive API calls might get you block.
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.