fix: dynamic import react-grid-layout to avoid SSR crash

WidthProvider is not available during SSR. Use dynamic import
inside useEffect to load it only on the client side.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hailin 2026-04-05 01:29:35 -07:00
parent 79c144d74b
commit b222429475
1 changed files with 18 additions and 8 deletions

View File

@ -1,9 +1,6 @@
'use client'; 'use client';
import React, { useMemo } from 'react'; import React, { useMemo, useState, useEffect } from 'react';
import { Responsive } from 'react-grid-layout';
// eslint-disable-next-line @typescript-eslint/no-require-imports
const WidthProvider = require('react-grid-layout').WidthProvider;
import { useAppSelector } from '@/adapters/state/redux/store'; import { useAppSelector } from '@/adapters/state/redux/store';
import { useLayout } from '@/frameworks/hooks/useLayout'; import { useLayout } from '@/frameworks/hooks/useLayout';
import { ChartWrapper } from '@/frameworks/components/charts/ChartWrapper'; import { ChartWrapper } from '@/frameworks/components/charts/ChartWrapper';
@ -13,8 +10,6 @@ import { useUIStore } from '@/adapters/state/zustand/uiStore';
import 'react-grid-layout/css/styles.css'; import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css'; import 'react-resizable/css/styles.css';
const ResponsiveGridLayout = WidthProvider(Responsive);
/** Placeholder shown when the canvas is empty. */ /** Placeholder shown when the canvas is empty. */
function DropZonePlaceholder() { function DropZonePlaceholder() {
const setImportModalVisible = useUIStore((s) => s.setImportModalVisible); const setImportModalVisible = useUIStore((s) => s.setImportModalVisible);
@ -46,6 +41,17 @@ function DropZonePlaceholder() {
export function CenterCanvas() { export function CenterCanvas() {
const charts = useAppSelector((s) => s.chart.charts); const charts = useAppSelector((s) => s.chart.charts);
const { layouts, onLayoutChange } = useLayout(); const { layouts, onLayoutChange } = useLayout();
const [GridLayout, setGridLayout] = useState<any>(null);
useEffect(() => {
import('react-grid-layout').then((mod: any) => {
const WP = mod.WidthProvider || mod.default?.WidthProvider;
const Resp = mod.Responsive || mod.default?.Responsive;
if (WP && Resp) {
setGridLayout(() => WP(Resp));
}
});
}, []);
const gridLayouts = useMemo(() => { const gridLayouts = useMemo(() => {
return layouts.map((item) => ({ return layouts.map((item) => ({
@ -73,9 +79,13 @@ export function CenterCanvas() {
); );
} }
if (!GridLayout) {
return <div style={{ padding: 16 }}>...</div>;
}
return ( return (
<div style={{ padding: 16, minHeight: '100%' }}> <div style={{ padding: 16, minHeight: '100%' }}>
<ResponsiveGridLayout <GridLayout
className="layout" className="layout"
layouts={{ lg: gridLayouts }} layouts={{ lg: gridLayouts }}
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }} breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
@ -91,7 +101,7 @@ export function CenterCanvas() {
<ChartWrapper chartId={chart.id} /> <ChartWrapper chartId={chart.id} />
</div> </div>
))} ))}
</ResponsiveGridLayout> </GridLayout>
</div> </div>
); );
} }