React-Grid-Layout中多Highcharts无法同步随网格缩放的问题求助
Hey there! Let's figure out why only one of your Highcharts is resizing with the grid, and fix this so all charts sync up properly.
The Root Cause
The problem boils down to shared React refs in your code. You're using this.conRef and this.myRef for every grid item in your map loop. Each time the loop runs, it overwrites these refs with the latest item—so by the end, only the last grid's container and chart are referenced. That's why only that one chart responds to resizing.
Solution 1: Use a Ref Array to Track Each Chart
We'll create an array to store unique refs for every grid container and its chart, then target the specific chart when its grid is resized.
Here's the updated code:
import React, { Component } from "react"; import { Responsive, WidthProvider } from "react-grid-layout"; import HighchartsReact from "highcharts-react-official"; import Highcharts from "highcharts/highstock"; import "./styles/styles.css"; const ResponsiveGridLayout = WidthProvider(Responsive); // Keep your data and config definitions here... export default class App extends Component { constructor(props) { super(props); // Initialize an array to hold refs for each grid item this.gridRefs = []; } handleResizeStop = (_, layoutItem) => { // Find the ref matching the resized grid's ID const target = this.gridRefs.find(ref => ref.id === layoutItem.i); if (target) { const { containerRef, chartRef } = target; if (chartRef.current && containerRef.current) { // Update the chart size to match its container chartRef.current.chart.setSize( containerRef.current.clientWidth, containerRef.current.clientHeight ); } } }; render() { const gridItems = [ { id: "1", name: "Item One" }, { id: "2", name: "Item Two" } ]; const layout = [ { i: "1", x: 0, y: 0, w: 2, h: 1, minW: 2, minH: 1 }, { i: "2", x: 5, y: 0, w: 2, h: 1, minW: 2, minH: 1 } ]; // Clear refs before re-rendering to avoid duplicates this.gridRefs = []; return ( <ResponsiveGridLayout layouts={{ lg: layout }} measureBeforeMount={true} className="layout" isDraggable={true} // Fixed typo: was isDragable isResizable={true} margin={[20, 20]} onResizeStop={this.handleResizeStop} > {gridItems.map((item) => { // Create unique refs for each grid container and chart const containerRef = React.createRef(); const chartRef = React.createRef(); this.gridRefs.push({ id: item.id, containerRef, chartRef }); return ( <div key={item.id} ref={containerRef} className="grid-item"> <HighchartsReact ref={chartRef} containerProps={{ style: { width: "100%", height: "100%" } }} options={config} highcharts={Highcharts} /> </div> ); })} </ResponsiveGridLayout> ); } }
Solution 2: Create a Reusable Grid Item Component (More Modular)
For a cleaner, more maintainable approach, wrap each chart in its own component that handles resizing internally using ResizeObserver. This way, you don't need to manage refs in the parent component at all.
First, create ChartGridItem.jsx:
import React, { useEffect, useRef } from "react"; import HighchartsReact from "highcharts-react-official"; import Highcharts from "highcharts/highstock"; const ChartGridItem = ({ options }) => { const containerRef = useRef(null); const chartRef = useRef(null); useEffect(() => { // Watch for container size changes const observer = new ResizeObserver((entries) => { entries.forEach(entry => { const { width, height } = entry.contentRect; if (chartRef.current) { chartRef.current.chart.setSize(width, height); } }); }); if (containerRef.current) { observer.observe(containerRef.current); } // Clean up observer on unmount return () => { if (containerRef.current) { observer.unobserve(containerRef.current); } }; }, []); return ( <div ref={containerRef} className="grid-item"> <HighchartsReact ref={chartRef} containerProps={{ style: { width: "100%", height: "100%" } }} options={options} highcharts={Highcharts} /> </div> ); }; export default ChartGridItem;
Then update your main App.jsx:
import React, { Component } from "react"; import { Responsive, WidthProvider } from "react-grid-layout"; import ChartGridItem from "./ChartGridItem"; import "./styles/styles.css"; const ResponsiveGridLayout = WidthProvider(Responsive); // Keep your data and config definitions here... export default class App extends Component { render() { const gridItems = [ { id: "1", name: "Item One" }, { id: "2", name: "Item Two" } ]; const layout = [ { i: "1", x: 0, y: 0, w: 2, h: 1, minW: 2, minH: 1 }, { i: "2", x: 5, y: 0, w: 2, h: 1, minW: 2, minH: 1 } ]; return ( <ResponsiveGridLayout layouts={{ lg: layout }} measureBeforeMount={true} className="layout" isDraggable={true} isResizable={true} margin={[20, 20]} > {gridItems.map((item) => ( <ChartGridItem key={item.id} options={config} /> ))} </ResponsiveGridLayout> ); } }
Quick Notes
- I fixed a typo in your original code:
isDragable→isDraggable(that's the correct prop name for react-grid-layout) - If you need to support older browsers, add a polyfill for
ResizeObserver(Solution 2) - Solution 2 is better for scalability—adding more charts later won't require changing the parent component logic
内容的提问来源于stack exchange,提问作者Gerald Goh

