Reputation: 2008
I have just started a new Next project, and I want to use a library called ReCharts.
However, whenever I use it in my project, even with one of the provided examples, it throws the following errors:
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: An error occurred during hydration. The server HTML was replaced with client content in `<div>`.
Warning: Prop `y` did not match. Server: "5" Client: "10.800000190734863"
at text
at Text (webpack-internal:///./node_modules/recharts/es6/component/Text.js:232:5)
at g
at Layer (webpack-internal:///./node_modules/recharts/es6/container/Layer.js:23:24)
at g
at g
at Layer (webpack-internal:///./node_modules/recharts/es6/container/Layer.js:23:24)
at CartesianAxis (webpack-internal:///./node_modules/recharts/es6/cartesian/CartesianAxis.js:77:5)
at svg
at Surface (webpack-internal:///./node_modules/recharts/es6/container/Surface.js:23:24)
at div
at CategoricalChartWrapper (webpack-internal:///./node_modules/recharts/es6/chart/generateCategoricalChart.js:920:7)
at SimpleBarChart
at main
at div
at Home
Here is my code:
const data = [
{
name: "Page A",
uv: 4000,
pv: 2400,
amt: 2400,
},
{
name: "Page B",
uv: 3000,
pv: 1398,
amt: 2210,
},
{
name: "Page C",
uv: 2000,
pv: 9800,
amt: 2290,
},
{
name: "Page D",
uv: 2780,
pv: 3908,
amt: 2000,
},
{
name: "Page E",
uv: 1890,
pv: 4800,
amt: 2181,
},
{
name: "Page F",
uv: 2390,
pv: 3800,
amt: 2500,
},
{
name: "Page G",
uv: 3490,
pv: 4300,
amt: 2100,
}
];
function SimpleBarChart(){
return (
<BarChart
id={1}
width={500}
height={300}
data={data}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Bar dataKey="pv" fill="#8884d8" />
<Bar dataKey="uv" fill="#82ca9d" />
</BarChart>
);
}
export default function Home(){
return (
<SimpleBarChart />
);
}
Note that this is copied and pasted in from here, so it should really "just work" out of the box.
Upvotes: 7
Views: 5231
Reputation: 4388
For those struggling with rendering the Pie
chart using @plutownium's answer, you need to use a hybrid of dynamic imports with ssr
disabled and regular importing:
import { Pie, Cell } from "recharts";
const PieChart = dynamic(
() => (
import("recharts").then(recharts => recharts.PieChart)
),
{
ssr: false
}
);
const Example = () => (
<PieChart width={100} height={100}>
<Pie data={data} {/* etc... */}>
{ data.map(entry => (
<Cell fill={entry.color} key={entry.key} />
))}
</Pie>
</PieChart>
);
This should prevent hydration warnings and allow the chart to render.
Upvotes: 4
Reputation: 780
I think the easiest setup is to have a custom client component that does all the Recharts rendering and then to just load that component (and only that one) dynamically with SSR off.
Please note that, in one of the answers, dynamic()
is called without defining a function for the first argument. That does not seem to work. (See also the documentation at https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading for examples.) Also note that adding .then()
after import()
is only needed if there is no default export that can be used.
Here is a sample server component that uses a chart rendered by a component called SimpleBars
:
import dynamic from 'next/dynamic'
const SimpleBars = dynamic(() => import('./bars-test'), { ssr: false })
export default function ChartSection() {
return (
<section>
<SimpleBars />
</section>
)
}
And here is the SimpleBars
component (in a file named bars-test.jsx
):
'use client'
import { BarChart, Bar } from 'recharts'
const data = [
{name: 'Category 1', series1: 400},
{name: 'Category 2', series1: 200},
{name: 'Category 3', series1: 500},
{name: 'Category 4', series1: 100},
]
export default function BarsTest() {
return (
<BarChart width={500} height={400} data={data}>
<Bar dataKey="series1" fill="#bcbcbc" />
</BarChart>
)
}
On the server side, this will be rendered as the following HTML, and the chart will then be drawn on the client side, without any hydration errors. This was tested with Next.js 14.0.3 and Recharts 2.9.3.
<section>
<template data-dgst="NEXT_DYNAMIC_NO_SSR_CODE" data-msg="NEXT_DYNAMIC_NO_SSR_CODE"></template>
</section>
Upvotes: 1
Reputation: 373
use the following to ensure Client-Side Rendering:
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
Upvotes: -1
Reputation: 1
You can try this. It solves my problem
const LineChart = dynamic(() => import('recharts').then(mod => mod.LineChart), {
ssr: false,
loading: () => <p>Loading...</p>
});
Upvotes: 0
Reputation: 2008
As @juliomalves says, the answer is to use dynamic imports with ssr
disabled:
import dynamic from "next/dynamic";
const SimpleBarChartWithoutSSR = dynamic(
import("../components/rechartsCharts/SimpleBar"),
{ ssr: false }
);
const SimpleScatterChartWithoutSSR = dynamic(
import("../components/rechartsCharts/SimpleScatter"),
{ ssr: false }
);
const DashedLineChartWithoutSSR = dynamic(
import("../components/rechartsCharts/DashedLine"),
{ ssr: false }
);
const PercentAreaChartWithoutSSR = dynamic(
import("../components/rechartsCharts/PercentArea"),
{ ssr: false }
);
Upvotes: 7