Search code examples
reactjsrecursionreact-grid-layout

react-grid-layout - child grid width


I have a CustomLayout component that renders itself recursively. It looks like this:

import "./styles.css";
import GridLayout from "react-grid-layout";
import React from "react";
import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";

export default function CustomLayout({ layout, onDragStart, onDragStop }) {
  const [isDraggable, setIsDraggable] = React.useState(true);

  return (
    <GridLayout
      className="layout"
      onDragStart={onDragStart}
      onDragStop={onDragStop}
      layout={layout}
      cols={12}
      rowHeight={80}
      width={1200}
      isDraggable={isDraggable}
    >
      {layout.map((item) => {
        if (item.children) {
          return (
            <div
              onClick={(e) => console.log(e.currentTarget.textContent[0])}
              key={item.i}
              style={{ background: "pink", border: "1px solid black" }}
            >
              <CustomLayout
                layout={item.children}
                width={item.w * 10}
                onDragStart={() => {
                  setIsDraggable(false);
                }}
                onDragStop={() => {
                  setIsDraggable(true);
                }}
              />
            </div>
          );
        } else {
          return (
            <div
              key={item.i}
              style={{ background: "purple" }}
              // onClick={(e) => console.log(item.i)}
            >
              {item.i}
            </div>
          );
        }
      })}
    </GridLayout>
  );
}

layout is an array that looks like this:

  const layout = [
    { i: "b", x: 0, y: 0, w: 3, h: 2, isResizable: true },
    { i: "c", x: 4, y: 0, w: 1, h: 2, isResizable: true },
    {
      i: "k",
      x: 0,
      y: 0,
      w: 6,
      h: 5,
      isResizable: true,
      children: [
        { i: "e", x: 0, y: 0, w: 2, h: 2, isResizable: true },
        {
          i: "d",
          x: 2,
          y: 4,
          w: 3,
          h: 4,
          isResizable: true,
          children: [
            { i: "e", x: 0, y: 0, w: 1, h: 1, isResizable: true },
            { i: "d", x: 1, y: 0, w: 1, h: 2, isResizable: true }
          ]
        }
      ]
    }
  ];

That is, the root elements of the array are displayed on the main grid, and if the element has an array of children, then a child grid is created recursively.
The question is: the main grid is 1200 px wide (width={1200}). I want to make the child grids have a width that is calculated by the formula width={item.w * 67}, I tried to just pass this to the child grid, but this does not work and its width is inherited from the parent. How can this logic be implemented?
P.S. Link to CodeSandbox: https://codesandbox.io/s/sleepy-brahmagupta-727w42


Solution

  • What you can do is instead of putting hard coded 1200 width in CustomLayout element get it through prop so you can directly choose desired width for each recursive call.

    • Accept prop named gridWidth in CustomLayout and pass it to GridComponent , now for outer width of 1200 , pass it from app when it first renders and then in recursive call just pass whatever you want (i.e item.w*67).

    here's code

    CustomLayout Component

    import "./styles.css";
    import GridLayout from "react-grid-layout";
    import React from "react";
    import "react-grid-layout/css/styles.css";
    import "react-resizable/css/styles.css";
    
    export default function CustomLayout({
      layout,
      onDragStart,
      onDragStop,
      gridWidth
    }) {
      const [isDraggable, setIsDraggable] = React.useState(true);
    
      return (
        <GridLayout
          className="layout"
          onDragStart={onDragStart}
          onDragStop={onDragStop}
          layout={layout}
          cols={12}
          rowHeight={80}
          width={gridWidth}
          isDraggable={isDraggable}
        >
          {layout.map((item) => {
            if (item.children) {
              return (
                <div
                  onClick={(e) => console.log(e.currentTarget.textContent[0])}
                  key={item.i}
                  style={{ background: "pink", border: "1px solid black" }}
                >
                  <CustomLayout
                    layout={item.children}
                    
                    onDragStart={() => {
                      setIsDraggable(false);
                    }}
                    gridWidth={item.w*67}
                    onDragStop={() => {
                      setIsDraggable(true);
                    }}
                  />
                </div>
              );
            } else {
              return (
                <div
                  key={item.i}
                  style={{ background: "purple" }}
                  // onClick={(e) => console.log(item.i)}
                >
                  {item.i}
                </div>
              );
            }
          })}
        </GridLayout>
      );
    }
    
    

    App Component

    import "./styles.css";
    import React from "react";
    import "react-grid-layout/css/styles.css";
    import "react-resizable/css/styles.css";
    import CustomLayout from "./gridLayout";
    
    export default function App() {
      const layout = [
        { i: "b", x: 0, y: 0, w: 3, h: 2, isResizable: true },
        { i: "c", x: 4, y: 0, w: 1, h: 2, isResizable: true },
        {
          i: "k",
          x: 0,
          y: 0,
          w: 6,
          h: 5,
          isResizable: true,
          children: [
            { i: "e", x: 0, y: 0, w: 2, h: 2, isResizable: true },
            {
              i: "d",
              x: 2,
              y: 4,
              w: 3,
              h: 4,
              isResizable: true,
              children: [
                { i: "e", x: 0, y: 0, w: 5, h: 1, isResizable: true },
                { i: "d", x: 1, y: 0, w: 1, h: 2, isResizable: true }
              ]
            }
          ]
        }
      ];
    
      return <CustomLayout layout={layout} gridWidth={1200} />;
    }