2

I'm working on creating some charts from some Notion databases. I have a nodejs backend that queries the Notion API and (I think) properly formats the data for use in chartjs. Then I have a frontend using react-chartjs-2. When I run the React app I get

TypeError: undefined is not an object (evaluating 'nextDatasets.map')
setDatasets — utils.ts:51
cloneData — utils.ts:85
renderChart — chart.tsx:44
(anonymous function) — chart.tsx:91
invokePassiveEffectCreate — react-dom.development.js:23487
callCallback — react-dom.development.js:3945
dispatchEvent
invokeGuardedCallbackDev — react-dom.development.js:3994
invokeGuardedCallback — react-dom.development.js:4056
flushPassiveEffectsImpl — react-dom.development.js:23574
unstable_runWithPriority — scheduler.development.js:468
(anonymous function) — react-dom.development.js:23324
workLoop — scheduler.development.js:417
flushWork — scheduler.development.js:390
performWorkUntilDeadline — scheduler.development.js:157
logCapturedError — react-dom.development.js:20085

If I output the data with console.dir it looks fine to me, but I could be wrong, so I'm not sure if I have a problem with the data or a problem with the react. Either way, can someone lend a hand to get past this error?

EDIT: I'm even more sure it's not the data, because I discovered I can go to the react-chartjs-2 vertical bar graph sandbox, plug in my data, and it just works. Turns out it's horrifically ugly because I structured the data wrong, but ... it should still work and not generate the above error. I guess it could still be a data error, but it seems very unlikely at this point.

App.js:

import { useState, useEffect } from 'react';
import { BarChart as Chart } from './components/Chart';
import './App.css';
  
export default function App() {
  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch('/api');
      const data = await res.json();
      console.dir(data, { depth: null });
      setChartData(data);
    }         
    fetchData();
  }, []);   
              
  const [chartData, setChartData] = useState({});
           
  return (
    <div className="App">
      <Chart chartData={chartData} />
    </div>
  );
}

EDIT: I updated Chart.js, thinking it might be a "Migration to v4" problem. If it is, then the changes I've made have been insufficient, because I still see the same problem. So far I'ave added the imports from chart.js and the ChartJS.register call. ./components/Chart.js:

import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend,
} from 'chart.js';
import { Bar } from 'react-chartjs-2';

ChartJS.register(
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend
);

export const BarChart = ({ chartData }) => {
  return (
    <div>
      <Bar
        data={chartData}
        options={{
          plugins: {
            title: {
              display: true,
              text: 'Visits by Link per Day'
            },
            legend: {
              display: true,
              position: "bottom"
           }
          }
        }}
      />
    </div>
  );
};

The data as they appear in the console log, from the react app:

Object
  datasets: Array (81)
    Object
      data: Array (10)
        0 0
        1 23
        2 3
        3 0
        ...
      label: "2021-08-27"
    Object
      data: Array (10)
        ...
      label: "2021-08-28"
    ...
  labels: Array (10)
    0 "label1 - - some data"
    1 "label2 - email - some other data"
    ...

The data as they appear in the browser if I hit my api endpoint directly:

{"labels":["label1 - - some data","label2 - email - some other data", ...],"datasets":[{"label":"2021-08-27","data":[0,23,3,0,1,0,1,2,0,0]},{"label":"2021-08-28","data":[0,0,0,0,0,0,0,0,0,0]},...,{"label":"2022-01-09","data":[0,0,25,0,0,0,0,0,0,0]}]}

Like I said, as far as I can see, the data are set up the same way as the example from chartjs.org, which in turn looks the same as the example that react-chartjs-2 gives. But I might just need another set of eyes. So, is there a problem with my data, or a problem with my app, or ... ¯\_(ツ)_/¯

This is with

react 17.0.2
chart.js 3.7.0
react-chartjs-2 4.0.0

Thanks!

philolegein
  • 1,099
  • 10
  • 28

1 Answers1

4

Turns out it was the very simple problem that the app was trying to render the component before the data had arrived, so I had to use some more state to check for data arrival before returning:

export default function App() {
  const [chartData, setChartData] = useState({});
  const [haveData, setHaveData] = useState(false); //here

  useEffect(() => { 
    const fetchData = async () => {
      try {
        const res = await fetch('/api');
        const data = await res.json();
        setChartData(data);
        setHaveData(true); // here, and importantly after the above setChartData call
      } catch(error) {
        setHaveData(false);
        setError(error);
      }
    }
    fetchData();
  }, []);

  if (!haveData) { // here
    return <div>Loading...</div>
  } else {
    return (
      <div className="App">
        <ErrorBoundary>
          <Chart chartData={chartData} />
        </ErrorBoundary>
      </div>
    );
  }
}

Easy fix, though not trivial to track down, and I'm a little bummed that the libraries don't handle the lack of data a little more gracefully.

philolegein
  • 1,099
  • 10
  • 28