I want to populate a grid with many different chart components (Chart1.js
, Chart2.js
, and so on ...) in react (using "react": "^18.2.0"
).
For these chart components, I reuse multiple components, including the FetchData.js
component which fetches the data from my node.js
server.
In most cases, it works fine. But especially when I did not ping the server for a while, the server as well as the database is in sleep mode (I’m using ‘heroku’) and needs some time to wake up, the charts are displaying the wrong data. Data is mixed up between the charts and some charts show different data than what the chart description says.
---------------------- EDIT ------------------------------
I think I might have narrowed down the issue to verifyIdToken
from firebase Admin SDK
in the backend (using node.js
v16.17.0
backend with express
^4.17.1
and firebase-admin: 11.2.0
).
I'm querying many different data series from a postgres
database (with knex
^1.0.1
).
After I do so I need to verify users idToken as I'm sending back either the complete database result or just parts of it, if the user is not authenticated.
router.get('endpoint/:reqData', (req, res) => {
const idToken = req.headers.authorization || "unauthorized";
db.select('dt',req.params.reqData).from('my_table').orderBy('dt')
.then(json => {
result = json.map(a => ([Date.parse(a['dt']), parseFloat(a[req.params.reqData])]))
getAuth()
.verifyIdToken(idToken)
.then((decodedToken) => {
res.send({
data: result,
name: req.params.reqData
})
})
.catch((error) => {
result = cut_result_to_unauthorised_user(result);
res.send({
data: result,
name: req.params.reqData
})
});
})
.catch(err => res.status(400).json('error getting ' + req.params.reqData + ' from my_table'))
})
When I skip the getAuth().verifyIdToken(idToken)
part, the data is returned as expected.
How do I chain the database query with knex
and the verifyIdToken
part correctly?
--------------------- EDIT END ---------------------------
Here are my other components:
The grid where I want to display all charts:
import React from "react";
import {
Grid,
} from "@mui/material/";
import { Chart1 } from "./Chart1";
import { Chart2 } from "./Chart2";
import { Chart3 } from "./Chart3";
import { Chart4 } from "./Chart4";
import { Chart5 } from "./Chart5";
import { Chart6 } from "./Chart6";
import { Chart7 } from "./Chart7";
import { Chart8 } from "./Chart8";
import { Chart9 } from "./Chart9";
export default function ChartsGrid() {
const data = {
charts: [
{ chart: <Chart1/> },
{ chart: <Chart2/> },
{ chart: <Chart3/> },
{ chart: <Chart4/> },
{ chart: <Chart5/> },
{ chart: <Chart6/> },
{ chart: <Chart7/> },
{ chart: <Chart8/> },
{ chart: <Chart9/> },
],
id: [1]
};
return (
<>
<div >
{data.id.map((elem) => (
<Grid
container
spacing={2}
direction="row"
justify="flex-start"
alignItems="flex-start"
key={elem}
>
{console.log(elem)}
{data.charts.map((elem2) => (
<Grid item xs={12} sm={6} md={4} lg={3} xl={3} key={data.charts.indexOf(elem2)}>
{console.log("index ",data.charts.indexOf(elem2)," : ", elem2.chart.type.name)}
{elem2.chart}
</Grid>
))}
</Grid>
))}
</div>
</>
);
}
One of the charts I show:
import PlainChart from '../PlainChart';
import Description from './Description';
import FetchData from '../FetchData';
import ChartTitel from './ChartTitle';
import ChartView from '../../pages/ChartView';
const chartName = 'My first chart'
const urls = ["myserver/endpoint/data_1_1", "myserver/endpoint/data_1_2"];
export default function Chart1(){
const data = FetchData({urls})
return(
<>
<ChartView
charttitle={<ChartTitel/>}
chart={
<PlainChart
chartName = {chartName}
data={data}
/>
}
desc={<Description/>}
/>
</>
)
}
I use a ChartView.js
which is a material UI
Card
component that displays the chart as well as some descriptions. The chart itself PlainChart.js
is also a component I reuse throughout all charts I'm displaying:
import React, {useState, useEffect } from "react";
import Highcharts from "highcharts/highstock";
import HighchartsReact from "highcharts-react-official";
import ChartLoadingScreen from '../ChartLoadingScreen'
export default function PlainChart({data}){
const HighchartsTheme = {
series: [ ]
};
const [isMounted, setMounted] = useState(false)
const [options, setOptions] = useState(HighchartsTheme)
useEffect(() => {
setMounted(false);
if(data){
options.series = [{ data: data[0]}];
options.series.push({ data: data[1]});
setOptions(prevState => ({ ...prevState}));
setMounted(true);
}
}, [data]);
return (
<>
<div>
{isMounted ?
<div>
<HighchartsReact
highcharts={Highcharts}
constructorType={"stockChart"}
options={options}
/>
</div>
:
<ChartLoadingScreen/>
}
</div>
</>
);
}
And finally the FetchData.js
:
import React, {useEffect, useState} from "react";
export default function FetchData({urls}){
const [data, setData] = useState(null);
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('GET', 'POST', 'OPTIONS');
useEffect(() => {
Promise.all(urls.map(u=>fetch(u, { headers: headers }))).then(responses =>
Promise.all(responses.map(response => response.json()))
).then(data => {
setData(data)
}
).catch(err => {
console.log(err)
}
);
}, []);
return data
}
Might also be important:
I show the charts not only in the grid but also throughout multiple places in the app.
Also I don't always use the PlainChart.js
for the chart itself, some custom charts require a custom Chart.js
, but I always use the ChartView.js
.