OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

How to render a React component inside of a Gridstack Widget?

  • Thread starter Thread starter user25699736
  • Start date Start date
U

user25699736

Guest
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

Code:
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

Code:
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

<p>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?</p>
<p>PORTAL EXAMPLE</p>
<pre><code>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
</code></pre>
<p>EXAMPLE RENDERING THE REACT COMPONENT DIRECTLY INSIDE THE WIDGET'S CONTENT</p>
<pre><code>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
</code></pre>
 

Latest posts

Top