Reputation: 1
I have the following issue: I am trying to render different React components (Rechart components with dummy data) inside some Gridstack widgets and I couldn't really find a staight forward example for doing that. I tried using React portals but I can't say I am very fond of this solution, since the portals are taken out of the normal component tree. I also tried rendering the components directly inside the content div, but it doesn't work (the widget sits on top of the chart). Is there some other way to render dynamic components inside Gridstack widgets?
PORTAL EXAMPLE
import React from "react"
import "gridstack/dist/gridstack.min.css"
import { GridStack } from "gridstack"
import "./GridStack1.css"
import { Button } from "@mui/material"
import LineChartExample, { IChartData } from "./LineChartExample"
import { createPortal } from "react-dom"
import BarChartExample from "./BarChartExample"
const enum ChartType {
Line = 0,
Bar = 1
}
interface IWidgetProps {
containerId: string
chartType: ChartType
chartData: IChartData[]
}
const Widget: React.FunctionComponent<IWidgetProps> = props => {
const { containerId, chartType, chartData } = props
const container = document.getElementById(containerId)
return container
? chartType === ChartType.Line
? createPortal(<LineChartExample data={chartData} />, container)
: createPortal(<BarChartExample data={chartData} />, container)
: null
}
const GridStackExample: React.FunctionComponent = () => {
const gridRef = React.useRef(null)
const [grid, setGrid] = React.useState<GridStack>()
const [widgetPortals, setWidgetPortals] = React.useState<JSX.Element[]>([])
React.useEffect(() => {
if (gridRef.current) {
const newGrid = GridStack.init(
{
float: true,
margin: 20,
resizable: {
handles: "e,se,s,sw,w"
}
},
gridRef.current
)
setGrid(newGrid)
}
const newPortals: JSX.Element[] = []
const items = [
{ id: "item1", w: 3, h: 3 },
{ id: "item2", w: 6, h: 3 },
{ id: "item3", w: 3, h: 3 },
{ id: "item4", w: 6, h: 3 },
{ id: "item5", w: 6, h: 3 },
{ id: "item6", w: 12, h: 4 }
]
items.forEach((item, index) => {
const el = document.createElement("div")
el.className = "grid-stack-item"
el.innerHTML = `<div class="grid-stack-item-content" id="${item.id}"> </div>`
if (index < 2) {
newPortals.push(
<Widget
key={item.id}
containerId={item.id}
chartData={[
{ name: "Page A", uv: 400, pv: 2400, amt: 2400 }
]}
chartType={ChartType.Line}
/>
)
} else {
newPortals.push(
<Widget
key={item.id}
containerId={item.id}
chartData={[
{ name: "Page A", uv: 400, pv: 2400, amt: 2400 }
]}
chartType={ChartType.Bar}
/>
)
}
grid?.addWidget(el, { w: item.w, h: item.h })
})
setWidgetPortals(newPortals)
return () => {
if (grid) {
grid.destroy()
}
}
}, [grid])
return (
<React.Fragment>
<div className="grid-stack" ref={gridRef}></div>
{widgetPortals}
</React.Fragment>
)
}
export default GridStackExample
EXAMPLE RENDERING THE REACT COMPONENT DIRECTLY INSIDE THE WIDGET'S CONTENT
import React from "react"
import "gridstack/dist/gridstack.min.css"
import { GridStack /* , GridStackWidget */ } from "gridstack"
import "./GridStack1.css"
import { Button } from "@mui/material"
import LineChartExample, { IChartData } from "./LineChartExample"
import BarChartExample from "./BarChartExample"
const enum ChartType {
Line = 0,
Bar = 1
}
interface IWidgetSetting {
id: string
chartType: ChartType
chartData: IChartData[]
}
function mapWidgetIdsToWidgetSettings(ids: string[]): IWidgetSetting[] {
const settings: IWidgetSetting[] = []
ids.forEach((id, index) => {
const setting: IWidgetSetting = {
id,
chartData: [{ name: "Page A", uv: 400, pv: 2400, amt: 2400 }],
chartType: index % 2 === 0 ? ChartType.Bar : ChartType.Line
}
settings.push(setting)
})
return settings
}
const Widget: React.FunctionComponent<IWidgetSetting> = props => {
const { id, chartType, chartData } = props
return (
<div className="grid-stack-item" data-gs-id={id}>
<div className="grid-stack-item-content">
{chartType === ChartType.Line ? (
<LineChartExample data={chartData} />
) : (
<BarChartExample data={chartData} />
)}
</div>
</div>
)
}
const GridStackExample: React.FunctionComponent = () => {
const gridRef = React.useRef(null)
const [grid, setGrid] = React.useState<GridStack>()
const [widgetSettings, setWidgetSettings] = React.useState<
IWidgetSetting[]
>([])
React.useEffect(() => {
if (gridRef.current) {
const newGrid = GridStack.init(
{
float: true
},
gridRef.current
)
setGrid(newGrid)
}
const items = [
{ id: "item1", w: 3, h: 3 },
{ id: "item2", w: 6, h: 3 },
{ id: "item3", w: 3, h: 3 },
{ id: "item4", w: 6, h: 3 },
{ id: "item5", w: 6, h: 3 },
{ id: "item6", w: 12, h: 4 }
]
items.forEach(item => {
const el = document.createElement("div")
el.setAttribute("data-gs-id", item.id)
el.className = "grid-stack-item"
el.innerHTML = '<div class="grid-stack-item-content"></div>'
grid?.addWidget(el, { w: item.w, h: item.h })
})
const widgetIds = items.map(i => i.id)
const gridWidgetsSettings = mapWidgetIdsToWidgetSettings(widgetIds)
setWidgetSettings(gridWidgetsSettings)
return () => {
if (grid) {
grid.destroy()
}
}
}, [grid])
return (
<React.Fragment>
<div className="grid-stack" ref={gridRef}>
{widgetSettings.map(setting => (
<Widget
key={setting.id}
id={setting.id}
chartData={setting.chartData}
chartType={setting.chartType}
/>
))}
</div>
</React.Fragment>
)
}
export default GridStackExample
Upvotes: 0
Views: 340