I have the following component which I then import and use in a page. Unfortunately I am getting the error error - TypeError: Cannot read property 'labels' of undefined
and data
and options
are underlined in the line where I pass them to ChartCard. I tried to follow the docs as close as I can but I guess I must be doing something wrong.
import faker from '@faker-js/faker'
import {
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineElement,
PointElement,
Title,
Tooltip,
} from 'chart.js'
import { Line } from 'react-chartjs-2'
import BaseCard from './BaseCard'
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
)
export async function getStaticProps() {
const options = {
responsive: true,
plugins: {
legend: {
position: 'top' as const,
},
title: {
display: true,
text: 'Price',
},
},
}
const labels = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
]
const data = {
labels,
datasets: [
{
label: 'Dataset 1',
data: labels.map(() => faker.datatype.number({ min: 2000, max: 4000 })),
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.5)',
},
],
}
return {
props: { options, data },
}
}
export default function ChartCard({ options, data }) {
return (
<BaseCard>
<Line options={options} data={data} />
</BaseCard>
)
}
Edit: I've now refactored my code to have the getStaticProps in the index.js page as follows:
#index.tsx
import type { NextPage } from 'next'
import faker from '@faker-js/faker'
import ChartCard from '../components/ChartCard'
export async function getStaticProps() {
const options = {
responsive: true,
plugins: {
legend: {
position: 'top' as const,
},
title: {
display: true,
text: 'IndexCoin Price',
},
},
}
const labels = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
]
const data = {
labels,
datasets: [
{
label: 'Dataset 1',
data: labels.map(() => faker.datatype.number({ min: 2000, max: 4000 })),
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.5)',
},
],
}
return {
props: { options, data },
}
}
const Home: NextPage = (options, data) => {
console.log(options)
console.log(data)
console.log(data.datasets)
return(
<ChartCard options={options} data={data} />
)
}
The console output of this is:
options: { responsive: true, plugins: { legend: [Object], title: [Object] } },
data: {
labels: [
'January', 'February',
'March', 'April',
'May', 'June',
'July'
],
datasets: [ [Object] ]
}
}
{}
undefined
And this crashes because datasets is undefined. Why is this happening?
CodePudding user response:
You can only use getStaticProps
in a NextJS page (i.e. component under src/pages/MyPageComponent.js).
(https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
This means that your ChartCard is being called with options=undefined and data=undefined as the getStaticProps
never runs.
It certainly would be nice to be able to encapsulate the server-side data fetching and rendering in one component file, but unfortunately this isn't possible right now.
What you'll need to do is to add an api to e.g. src/api/MyApi.js
and call that in your component.
E.g. a quick example to start from:
src/api/MyApi.js
export default function MyApi(req, res) {
//... do your data fetching
res.send({options, data})
}
src/components/MyComponent.js
const [result, setResult] = useState();
useEffect(async ()=>{
const res = await fetch('/api/MyApi');
const result = await res.json();
setResult(result);
}, []);
const {options, data} = result ?? {};
Note the above will perform client-side data fetching so will need a live server.
If you're expecting to build static pages at build time then your only option (IIRC) is to capture ALL the data needed in the src/pages/MyPage.js's getStaticProps and pass them into the page's components as needed.
CodePudding user response:
if this code is exact copy of your project there is a typo in it:
position: 'top' as const
try this:
position: 'top as const'
and also use getStaticProps
for page components