'I can't seem to pass an array of objects as prop (console logs 1 object, [object object] instead)

I am new to React js and I am trying to pass my data(dummy_data) as props from App.js to PieChart.js so that I can access the data from PieChart.js. dummy_data is an array of objects, dummy_data={[object Object] [object Object] ... [object Object]}.

I am confused as to why I am only able to see 1 object pair from my console log in PieChart, [object Object]. What do I need to do to pass the dummy_data object array to my PieChart function in PieChart.js?

I have tried the passing of a normal array the syntax , but my console log in PieChart.js still shows me the same output [object Object]. Am I using the syntax wrongly?

App.js

import React from "react";
import axios from "axios";

// imports
import PieChart from './components/piechart'; // Piechart for dashboard

/*
Info:
"data" contains all MongoDB data read from /api call, which uses find({ }) to search MongoDB for all data.
"data" is an array of objects in the format Data: { [object object], [object object] ... [object object] }
getInOutEnv(item) {} is used to map the "data" retrieved from /api call. The resulting response allows me to
access each object in "data" as "item" and accessing the object's properties using item (item.environment and item.lightlevel)
*/

// app class
class App extends React.Component {

  // Accessing values/var from functions
  dummy = []; // store response data from /api (server/MongoDB)
  dummy_final = []; // store previous data of dummy and check to see if they hold the same values
  map = [];   // store data in mapped format to be able to access object properties (e.g. trythis.env and trythis.lightlv)
  
  getInOutEnv(item) {
    console.log( 'obj - ' + [item.environment,item.lightlevel].join(" ") );
    let inOut = {env: item.environment, lightlv: item.lightlevel};
    return (inOut);
  }

  getData() {
    axios.get('/api')
      .then((response) => {
        const data = response.data; //contains all the data from MongoDB
        console.log('---------- <Get Data> ----------');
        console.log(`data : ${data}`);
        console.log(`map : ${this.map}`);
        // try 1
        this.dummy = data;  // data and dummy are an array of objects -> Data: { [object object] [object object] ... [object object]}
        console.log(`[dummy] ${this.dummy}`);
        let map = this.dummy.map(this.getInOutEnv);
        console.log('----- accessing obj properties -----')
        if (JSON.stringify(this.dummy) !== JSON.stringify(this.dummy_final)) {
          console.log(`[dummy] ${JSON.stringify(this.dummy)}`);
          console.log(`[dummy_final] ${JSON.stringify(this.dummy_final)}`); // check if difference between dummy and dummy_final
          ...
            //increase count of lightlv
            switch(trythis.lightlv) { // 6 cases 'Bright', 'Dark', 'Normal', 'VerySunny', 'Outcast', 'Sunny'
              ...
            }
          }
          // set dummy to dummy_final, so this loop will not trigger unless new data is fetched to dummy from /api (MongoDB)
          this.dummy_final = this.dummy;
          console.log(`[new dummy_final] ${JSON.stringify(this.dummy_final)}`);
        } else {
          console.log('[Data stored is up to date] Values of MongoDB matches current data stored in dummy_final');
          console.log(`[Current Env Indoor] ${this.envCount_Indoor}`);  // check count of env indoor
          console.log(`[Current Env Outdoor] ${this.envCount_Outdoor}`);  // check count of env outdoor
          console.log(`[Current Env Mismatched Field Names] ${this.envCount_Error}`);  // check count of mismatched Field Names
        }
      })
      .catch(() => {
        alert('Error in retrieving data');
      });
  }

  render() {

    this.getData();
    console.log(`[testingData] ${this.dummy_final}`);

    return(
        <div className="App">
          Pie Chart
          <PieChart dummy_final={this.dummy_final}/>
        </div>
    )
  }
}
 
export default App;

PieChart.js

import React from "react";
import { Pie, Doughnut } from 'react-chartjs-2';
import { Chart, ArcElement } from "chart.js";
Chart.register(ArcElement);


// chart background colour for env
const bgcolour_env = [
    'rgba(255, 99, 132, 0.2)',  //colour 1...
    'rgba(54, 162, 235, 0.2)',  
    'rgba(255, 206, 86, 0.2)',
    'rgba(75, 192, 192, 0.2)',
    'rgba(153, 102, 255, 0.2)',
    'rgba(255, 159, 64, 0.2)'   //last colour
]

const hover_env = [
    'rgba(255, 99, 132, 0.8)',  //colour 1...
    'rgba(54, 162, 235, 0.8)',  
    'rgba(255, 206, 86, 0.8)',
    'rgba(75, 192, 192, 0.8)',
    'rgba(153, 102, 255, 0.8)',
    'rgba(255, 159, 64, 0.8)'
]

// chart background for lightlevel

const data = {
    labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
    datasets: [{
        data: [12, 19, 3, 5, 2, 3],
        backgroundColor: bgcolour_env,
        hoverBackgroundColor: hover_env
    }]
}

function PieChart({dummy_final}) {
  let data1 = [];
  data1 = dummy_final;
  console.log(`dummy_final : ${dummy_final}`);
  //console.log(`data1 : ${JSON.stringify(data1)}`);

  return (
      <div>
        test
        <Doughnut 
        data={data}
        options={{
          title:{
            display:true,
            text:'Average Rainfall per month',
          },
          legend:{
            display:true,
            position:'right'
          }
        }}
        />
      </div>
  );
}
  
export default PieChart;


Solution 1:[1]

UPDATE!

I realised that using setState here would actually be easier to pass the data and is the more ideal way of passing my data since it is part of the React Lifecycle (still have no clue how to pass a promise's returned data).

App.js

import React from "react";
import axios from "axios";

// import from components
import PieChart from './components/piechart'; // Piechart for dashboard

class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      environment: '',
      lightlevel: '',
      data_form: []
    };
  }


  // Accessing values/var from functions
  dummy = []; // store response data from /api (server/MongoDB)
  dummy_final = []; // store previous data of dummy and check to see if they hold the same values


  getData() {
    return axios.get('/api')
      .then((response) => {
        const data = response.data; //contains all the data from MongoDB
        this.dummy = data;
        console.log(`[data] : ${data}`);
        console.log(`[check dummy] ${this.dummy}`);
        console.log('---------- <Get Data> ----------');
        // Checking if dummy and dummy_final have the same data. If they do, do not retrieve data. If not retreieve and set data.
        if (JSON.stringify(this.dummy) !== JSON.stringify(this.dummy_final)) {
          this.setState({
            data_form: this.dummy
          });
          console.log('Reached');
          this.dummy_final = this.dummy;
          console.log(`[dummy_final] ${this.dummy_final}`);
        } else {
          console.log('Data up to date');
          console.log(`[Current Data] ${this.dummy_final}`);
        }
      })
      .catch(() => {
        alert('Error in retrieving data');
      });
  }


  render() {

    this.getData();

    console.log(`[state data] ${this.state.data_form}`);


    //JSX
    return(
        <div className="App">
          Pie Chart
          <PieChart data_form={this.state.data_form}/>
        </div>
    )
  }
}

export default App;

Since you cannot call upon useEffect in Class Component, I just used a conditional statement to compare this.dummy and final_dummy after assigning this.dummy to my response.data from my /api call, at the start since this.dummy will be assigned response.data, the conditional statement returns false, thereby triggering the function to setState with this.dummy as the data and assigning this.dummy to this.dummy_final. After which since calling a useState will result in an infinite render loop, I fixed this with the conditional statement such that will since this.dummy is now = this.dummy_final, the condition is false and will not trigger the setState conditional block, thereby preventing an infinite loop. (This method is basically just replicating useEffect hook in Component Class without encapsulating a functional component)

PieChart.js

import React from "react";

function PieChart(props) {
  console.log(`data_form : ${props.data_form}`);
  ...


  return (
      <div>
        ...
      </div>
  );
}
  
export default PieChart;

Hope this helps anyone who ran into the same issue starting React without an experience.

Feel free to leave some links to some useful information about the latest React workflow. I would greatly appreciate it, Cheers!

Solution 2:[2]

About useEffect, if you'd look the link that I left on my comment, you'd see that it combines two class methods componentDidMount and componentDidUpdate, actually it has componentWillUnmount there too, try something like this:

import React from "react";
import axios from "axios";

import PieChart from './components/piechart'; // Piechart for dashboard

class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      environment: '',
      lightlevel: '',
      data_form: [],
    };
  }

  getData() {
    axios.get('/api')
      .then((response) => {
        const data = response.data; //contains all the data from MongoDB
        this.setState({
          data_form: data,
        }); 
      })
      .catch((error) => alert('Error in retrieving data', error));
  }

  componentDidMount() {
    this.getData();
    console.log(`did mount [state data] ${this.state.data_form}`);
  }

  componentDidUpdate() {
    this.getData();
    console.log(`did update [state data] ${this.state.data_form}`);
  }

  render() {
    return(
      <div className="App">
        Pie Chart
        <PieChart data_form={this.state.data_form}/>
      </div>
    )
  }
}

export default App;

Can't test it myself without the project, but I think it should work.

UPDATE: (SAME CODE WITH FUNCTIONAL COMPONENTS)

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

// import from components
import PieChart from './components/piechart'; // Piechart for dashboard

function App()  {
  const [dataForm, setDataForm] = useState([]);

  getData() {
    axios.get('/api')
      .then(({ data }) => {
        setDataForm(data); 
      })
      .catch((error) => alert('Error in retrieving data', error));
  }

  useEffect(() => {
    getData()
    console.log(`will be called once on first render [state data]: ${dataForm}`);
  }, [])

  return (
    <div className="App">
      Pie Chart
      <PieChart data_form={dataForm}/>
    </div>
  )
}

export default App;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Lucas Pang
Solution 2