jakobarsement
jakobarsement

Reputation: 139

Why is React not treating my array properly?

When I render this React component:

import React, { useState, useEffect, useCallback } from "react";

// import RenderLineChart from "../recharts/rechart.component";
import axios from "axios";

import "./chart-item.styles.scss";

const ChartItem = ({ apiUrl }) => {
    const [chartData, setChartData] = useState([]);

    //function that pulls data from APIs
    const loadChartData = useCallback(() => {
        axios.get(apiUrl).then((response) => {
            setChartData(response.data);
        });
    }, [apiUrl]);

    //runs initial pull from API
    useEffect(() => {
        loadChartData();
    }, [loadChartData]);

    console.log("Raw Data: ");
    console.log(chartData);

    console.log("Array: ");
    console.log(chartData.historical);

    // console.log("Array Element: ");
    // console.log(chartData.historical[0]);

    return <div className="chart"></div>;
};

export default ChartItem;

The console output is such: enter image description here

When I uncomment that third console.log statement and save the component file without refreshing localhost, the output is:

enter image description here

But when I actually refresh the localhost tab, the output is such:

enter image description here

As if it is no longer being treated as an array. Can anyone explain what's going on here?

Upvotes: 0

Views: 157

Answers (1)

Federico Vitale
Federico Vitale

Reputation: 380

You have 2 mistakes in the snippet you posted.

  1. You're declaring chartData as an array, but then you're updating it with an object (inside the loadChartData function)

  2. When page loads the console.log is executed before the loadChartData function has completed the request, so at the first render chartData = [] and chartData[0] = undefined, but if you try to get chartData.historical[0] it throws you an error because it is defined as an array.

So, how can you fix this? The answer is pretty straightforward, first of all you have to use a consistend data-type for your state, if it's an array when declared, then when you update it, pass an array, if not you'll always have this kind of problems. This should fit your needs. If you want to log chartData everytime it upates you just need to write a new useEffect with the console.log inside and chartData as "dependency"

const [chartData, setChartData] = useState({ historical: [] })

// declare you api call
const apiCall = useCallback(() => {
  try {
    const response = await axios.get(url);
    setChartData(response.data)
  } catch (e) {
    console.error(e)
  }
}, [setChartData])

useEffect(() => {
  apiCall()
}, [apiCall])

useEffect(() => {
  console.log("Raw Data: ");
  console.log(chartData);

  console.log("Array: ");
  console.log(chartData.historical);

  console.log("Array Element: ");
  console.log(chartData.historical[0]);
}, [chartData])

// do you stuff with jsx

I suggest you to take a look at Hooks Documentation

Hope this helps ✌️

Upvotes: 1

Related Questions