'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 |