React-grid-layout: Changing x, y, w, h or static in state does not trigger layout update

Created on 6 Dec 2019  路  10Comments  路  Source: STRML/react-grid-layout

I'm storying data-grid attributes in state. When a programmatically change the values, the layout is not updated.

stale

Most helpful comment

I solved the issue I had. May be this will help somebody else having troubles with changing x, y, w or h dynamically on existing items:

What I was doing before: I was using the responsive version of RGL:

import {Responsive, WidthProvider} from 'react-grid-layout';
const ReactGridLayout = WidthProvider(Responsive);
...

<ReactGridLayout ...

and I also needed the abilities to dynamically add Items, to be able to resize the programmatically depending on content and to load pre-filled grid on first load, i.e. there were already items there, the grid was not empty initially (sometimes). I got all three features work only if I provided both the layout property on RGL and data-grid property on each item individually.

After some research, I've found a sandbox (and modified it a bit) which made clear, that programmatically changing item properties works, at least with the non-responsive version of RGL: https://codesandbox.io/s/fancy-tdd-9znir

The first caveat is to truly change the layout, i.e. provide completely new layout array after modifying an item in it. So if you just change an item in the layout and provide the same layout (with a modified item though) - it won't affect RGL. So this won't work:

...
testChangeHProgrammatically = () => {
    const layout = this.state.layout;
    layout[0].h = 3;

    this.setState({ layout });
};
...

But this instead, will work:

...
testChangeHProgrammatically = () => {
    const layout = this.state.layout.map(item => ({ ...item }));
    layout[0].h = 3;

    this.setState({ layout });
};
...

But this is not what I've found out, this fact was discussed and linked in some other issue, I sadly can't find it anymore for the credits.

Furthermore there was another big problem in approach I used and that's what finally solved my issue. But that was actually my fault because I didn't read the docs (https://github.com/STRML/react-grid-layout#responsive-usage) properly. So the key was to use layouts property instead of layout, when using the responsive version of RGL. After I changed it form <RGL layout={layout}> to <RGL layouts={lg: layout}> - the changes were taken into account each time I changed the item properties. The data-grid property on the items was also not needed anymore.

I can create a sandbox if somebody still needs it.

All 10 comments

I was trying to figure out the same thing to adjust the height dynamically based on the contents of the "Grid-Item".

In the Grid-Item component, I have a callback that sends it's scroll height to the parent. The parent stores the pixel height in it's state.

Then, I programmatically changed the values (in my case the height of a GridItem) in the onLayoutChange method before saving the layout to the state.

Hope that helps :)

@superadminfabian can you give us a code example please?

edit: thank you superadminfabian for the comment, that's the trick. Now I get the height dynamically :-)

@superadminfabian @paddibr

sorry, I still don't get it - is your solution a workaround in which you control directly the pixel height or are you controlling the h property? Because if one programmatically changes the h property of an item and it is reflected in the layout property of the RGL - it still doesn't affect what is displayed on screen.

@aepp I wrote a new solution because with onLayoutChange I just get buggy divs (grid items). First I set a initial "layouts". When a grid item is now resizing in his height, I call my own new function "onXYResize" and set a new h property in my layouts. It works really good and stable. If you minimalize your browser it still works e.g.

In my resize function I calculate the actual div height and calculate then the h property and set it to layouts.

I have this and for me it doesn't work either.
I am trying to make the second div take up all of the available space after resizing the first one.

const defaultMainVizSize = { h: 10, w: 16 };
const mainVizKey = 'explore-main-viz';

const ExplorePage = () => {
  const [vizId] = useQueryParam('id', NumberParam);
  const [mainVizSize, setMainVizSize] = useState(defaultMainVizSize);
  console.log('mainVizSize', mainVizSize);
  return (
    <div>
      <ResponsiveGridLayout
        cols={GRID_COLS_NUMBER}
        rowHeight={GRID_ROW_HEIGHT}
        isDraggable={false}
        onLayoutChange={layout => {
          layout.forEach(l => {
            if (l.i === mainVizKey) {
              setMainVizSize({ w: l.w, h: l.h });
            }
          });
        }}
      >
        <div
          style={{ border: '1px dashed black' }}
          key={mainVizKey}
          data-grid={
            {
              ...mainVizSize,
              x: 0,
              y: 0,
              isResizable: true
            } as ReactGridLayout.Layout
          }
        >
          Main viz here
        </div>
        <div
          style={{ border: '1px solid black' }}
          key="drilldown-viz"
          data-grid={{
            x: mainVizSize.w,
            y: 0,
            w: GRID_COLS_NUMBER - mainVizSize.w,
            h: mainVizSize.h,
            isResizable: false
          }}
        >
          Select an element from the main viz to view it here
        </div>
      </ResponsiveGridLayout>
    </div>
  );
};

I solved the issue I had. May be this will help somebody else having troubles with changing x, y, w or h dynamically on existing items:

What I was doing before: I was using the responsive version of RGL:

import {Responsive, WidthProvider} from 'react-grid-layout';
const ReactGridLayout = WidthProvider(Responsive);
...

<ReactGridLayout ...

and I also needed the abilities to dynamically add Items, to be able to resize the programmatically depending on content and to load pre-filled grid on first load, i.e. there were already items there, the grid was not empty initially (sometimes). I got all three features work only if I provided both the layout property on RGL and data-grid property on each item individually.

After some research, I've found a sandbox (and modified it a bit) which made clear, that programmatically changing item properties works, at least with the non-responsive version of RGL: https://codesandbox.io/s/fancy-tdd-9znir

The first caveat is to truly change the layout, i.e. provide completely new layout array after modifying an item in it. So if you just change an item in the layout and provide the same layout (with a modified item though) - it won't affect RGL. So this won't work:

...
testChangeHProgrammatically = () => {
    const layout = this.state.layout;
    layout[0].h = 3;

    this.setState({ layout });
};
...

But this instead, will work:

...
testChangeHProgrammatically = () => {
    const layout = this.state.layout.map(item => ({ ...item }));
    layout[0].h = 3;

    this.setState({ layout });
};
...

But this is not what I've found out, this fact was discussed and linked in some other issue, I sadly can't find it anymore for the credits.

Furthermore there was another big problem in approach I used and that's what finally solved my issue. But that was actually my fault because I didn't read the docs (https://github.com/STRML/react-grid-layout#responsive-usage) properly. So the key was to use layouts property instead of layout, when using the responsive version of RGL. After I changed it form <RGL layout={layout}> to <RGL layouts={lg: layout}> - the changes were taken into account each time I changed the item properties. The data-grid property on the items was also not needed anymore.

I can create a sandbox if somebody still needs it.

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this issue will be closed in 7 days

@aepp Thanks a bunch you saved me hours 馃嵒

@aepp Thanks a lot for this. I know it;s been awhile, abut are you still able to create a sandbox that demonstrates the use with a ResponsiveGridLayout?
I've tried implementing it but my whole page refreshes when I update the width of one grid item.

Thanks again.

=== EDIT ===

Never mind, I got it working. Thanks!

Was this page helpful?
0 / 5 - 0 ratings