Friday, February 23, 2024
 Popular · Latest · Hot · Upcoming
89
rated 0 times [  95] [ 6]  / answers: 1 / hits: 5746  / 3 Years ago, thu, october 15, 2020, 12:00:00

I'm getting an error when my chart component renders due to its initial state which is an empty array before the API response. It would say something like Cannot read property '0' of undefined which is due to the fact that when the component loads, its initial state is, well... an empty array. So I'd like to know if there's a way to make the component render only after the API response is received.


Here is the parent component:


function InformationPage({
match: {
params: { symbol },
},
}) {

const [chartData, setChartData] = useState([]); {/*Declaring state*/}

useEffect(() => { {/*Fetching API response here to set state*/}
axios
.get(
`https://finnhub.io/api/v1/stock/candle?symbol=${symbol}&resolution=15&from=1572651390&to=1602623478&token=xxxxxxxxx`
)
.then((res) => {
console.log(res.data);
setChartData(res.data);
})
.catch((err) => {
console.log(err);
});
}, [symbol]);

return (

<Grid item container xs={12} sm={12} md={6} lg={8}>
{chartData && <QuoteChart chartData={chartData} iex={iex} />}
</Grid>

);
}
export Default InformationPage;

Here is the child chart component, basically when I do the fetch request from axios it returns an array that will get mapped in the chartRender object. I just need to find a way to render the component only AFTER the api request from axios is finished as to not have an error. Any help would be greatly appreciated.


function QuoteChart(props) {
const classes = useStyles();
const { chartData } = props;

const chartRender = chartData.map((chartConfig) => ({
x: new Date(chartConfig?.t),
y: [chartConfig?.o, chartConfig?.h, chartConfig?.l, chartConfig?.c],
}));

// const chartDataLog = console.log(chartData);
const config = {
series: [
{
data: [{ chartRender }],
},
],

More From » reactjs

 Answers
21

Update: According to Finnhub API it's an object that you receive from the API, not an array. This means that charData.length in my previous answer will never be evaluated to true and the child component QuoteChart will never get rendered.


I'd suggest the following changes. In your parent component, make charData = null initially:


const [chartData, setChartData] = useState(null);

When the API has returned a response and chartData has been assigned a value your child component can be rendered:


{chartData && <QuoteChart chartData={chartData} iex={iex} />}

The chart you want to render in the child component expects the following input: [{ x: date, y: [O,H,L,C] }]. Because map() can only be called on arrays and chartData is not one, you should navigate to one of the arrays inside the said object, e.g. chartData.t:


const chartRender = chartData.t.map((timestamp, index) => ({
x: new Date(timestamp),
y: [chartData.o[index], chartData.h[index], chartData.l[index], chartData.c[index]],
}));

Finally, series.data expects an array, you don't need to additionally wrap it in an object. So this should work:


const config = {
series: [{
data: chartRender
}]
};



You initialize chartData with an empty array, therefore your condition should look like this:


{chartData.length && <QuoteChart chartData={chartData} iex={iex} />}

If you expect the API to return an empty list, I'd recommend to set an undefined or null as the initial value of chartData:


const [chartData, setChartData] = useState(null);

In this case you can keep your condition as is.


[#2482] Sunday, October 11, 2020, 3 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
victorr

Total Points: 193
Total Questions: 86
Total Answers: 105

Location: Pitcairn Islands
Member since Thu, Jun 24, 2021
3 Years ago
victorr questions
Fri, Nov 13, 20, 00:00, 3 Years ago
Sat, Jul 25, 20, 00:00, 4 Years ago
Thu, Jun 11, 20, 00:00, 4 Years ago
Mon, Aug 19, 19, 00:00, 5 Years ago
;