Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update layout when props changed #382

Closed
ghost opened this issue Oct 21, 2016 · 29 comments
Closed

Update layout when props changed #382

ghost opened this issue Oct 21, 2016 · 29 comments
Labels
stale The label to apply when a pull request or an issue is stale

Comments

@ghost
Copy link

ghost commented Oct 21, 2016

How to update layout programmatically? Currently, when i try to set new layout to GridLayout it will be ignored
This is new props that i provided
image
This is yours component state after i provided new layout
image

As you can see, props are just ignored, all i need to do is to change children isDraggable on button click
I tried to do the same with inline grid, but it had no effect

@nikolas
Copy link
Contributor

nikolas commented Oct 24, 2016

I'm having a similar problem: when I'm giving my GridItems a new width via data-grid, the width of the displayed item remains the same even though the props have changed and the grid is re-rendered. I'll write here if I come up with a solution.

Also, I'm not sure, but this is possibly related to this issue: #178 which has apparently been resolved.

@STRML
Copy link
Collaborator

STRML commented Oct 24, 2016

@nikolas If you can get a working webpackbin going (here's one for react-resizable) it would be really helpful for debugging this.

@nushydude
Copy link

nushydude commented Oct 27, 2016

I had the same issue. Ended up using the layout props (i.e. updating the layout array with new values) of ReactGridLayout component instead of data-grid prop on each widget component.

@ghost
Copy link
Author

ghost commented Nov 3, 2016

@nushydude i did the same but it did not work as i expected, so i just rerender whole component when need, it`s bad solutions, but it works

@STRML
Copy link
Collaborator

STRML commented Nov 14, 2016

Here is a webpackbin, please demonstrate the issue: http://www.webpackbin.com/VymTE3zWG

@nikolas
Copy link
Contributor

nikolas commented Nov 30, 2016

I would like to come up with an example but I can't get webpackbin to work at the moment. I've opened an issue with that project here: christianalfoni/webpack-bin#199

nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue Dec 14, 2016
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
@nikolas
Copy link
Contributor

nikolas commented Dec 14, 2016

If anyone is still wondering, there's a small change you can make in processGridItem() to solve this problem:
ccnmtl@c44f3f2

I haven't opened a pull request for this yet because, although it works for my case, I haven't tested this while using the global layout array - this may override that in unwanted ways.

nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue Dec 20, 2016
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue Dec 20, 2016
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue Dec 21, 2016
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue Dec 22, 2016
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
@nikolas nikolas mentioned this issue Jan 24, 2017
2 tasks
@developer94404
Copy link

developer94404 commented Feb 15, 2017

I'm currently encountering this issue as well. My application state updates the layouts passed to the grid items' data-grid, but no re-render is caused.

Even adding layout to this.state and setting layout={this.state.layout} did not fix it (perhaps because my grid items are still using their data-grid).

I will try to apply the patch kindly provided by @nikolas above.

PS: I am using ResponsiveGridLayout

@developer94404
Copy link

Hmm, this patch doesn't seem to work for me. It breaks the grid functionality. @nikolas am I doing something wrong?

@developer94404
Copy link

developer94404 commented Feb 15, 2017

@STRML - I've modified your webpackbin to have a load and save layout buttons; I can't seem to get the layout to update dynamically after loading the saved layout from storage. May you kindly take a look?

http://www.webpackbin.com/418oyspOf

Thank you

EDIT: It doesn't work if you 'save', then drag the layout around a bit, then click 'load'. It does work if you 'save', then click 'generate new layout', then click 'load'.

nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue Feb 20, 2017
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
@developer94404
Copy link

@nikolas there are a few different issues going on; for the way I'm using react-grid-layout, the patch above does not work because the re-render caused by setState isn't even triggered. (setState isnt called)

@developer94404
Copy link

@STRML
I've made a patch that fixes the issue for myself, but its extremely hacky. I believe @nikolas 's patch is the proper way to go, but for some reason, it doesn't work for me.

For me, I've made these changes:

utils.js:
export function childrenEqual(a: ReactChildren, b: ReactChildren): boolean {
var keyEquals = isEqual(React.Children.map(a, c => c.key), React.Children.map(b, c => c.key));
var dataGridEquals = isEqual(React.Children.map(a, c => c.props['data-grid']), React.Children.map(b, c => c.props['data-grid']));
var equals = keyEquals && dataGridEquals;
return equals;
}

  1. utils.js :: synchronizeLayoutWithChildren:
    Comment out the following if-block:
    // if (exists) {
    // layout[i] = cloneLayoutItem(exists);
    // } else {

This does two things:

  1. Does not compare for child changes only by child key -- must also check child data-grid equality
  2. Ignore existing layout when synchronizing layouts in componentwillReceiveProps(). The current code wlil always set the layout according to the current layout state, but what if you are setting your child items' data-grid positions (ie, when you are 'loading' a grid from memory?) -- you need to ignore the current layout and always use the chlidren's data-grid layouts.

However, the above will cause issues (I think) for those using the prop ReactGridLayout.prop.layout (I don't use it).

So, the fixes above are kludges and only use it if you aren't using the prop 'layout'.

nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue Feb 21, 2017
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
@developer94404
Copy link

developer94404 commented Feb 28, 2017

I just wanted to leave some notes to help out, here.

So, you can get it to work properly, if you follow the exact use-case in "example 7: loading and storing".

The error others have made is:

  1. Assuming you can purely load elements off of data-grid={layout object} (here, the prop layout (for ReactGridLayout) / layouts (for ResponsiveGridLayout) are NOT being used)

  2. Assuming you can purely use the prop layout / layouts *without using data-grid={layout object}

In actuality, you must use BOTH the prop layouts / layout AND data-grid={layout object}, in order to get state storage to work as is:

  1. In whatever memory object you are using to track items' layouts, you MUST pass these layout objects to the ReactGridLayout/ResponsiveGridLayout's "layout/layouts" prop
  2. In addition, you MUST still specify data-grid={el.layout} (if you do NOT do this, the grid layout does NOT update correctly even if you specify updated values for the layout/layouts prop.

Doing the above #1 and #2 will ensure you can use the current (as of Feb 2017) code base without doing any custom patching.

EDIT: Actually, this still doesn't work fully. You must apply my patch above, and then it will work regardless of if you do #1 or #2 or both #1 and #2.

@john-hu
Copy link

john-hu commented Mar 17, 2017

@nikolas I found yours introduces another issues. After I applied the patch, the grid layout cannot resize/drag anymore. I can resize or drag item but it goes back to original place when I release it.

@ThomasChan
Copy link

I did @developer94404 said 1 and 2, and it did work for me.

@pkerpedjiev
Copy link

I was having a similar issue until I realized that I was changing the layout object that was used as a prop for ReactGridLayout. It went something like this:

this.state.myLayout.x += 2;

<ReactGridLayout
    layout={this.state.myLayout}
>
    {children}
</ReactGridLayout>

The problem was that ReactGridLayout.js uses componentWillUpdate to check if the props have changed. Since I was modifying the layout object in place, in componentWillUpdate, nextProps were always equal to this.props causing the layout to remain the same.

To fix this, I calculate a fresh layout object to pass as a prop to ReactGridLayout:

let newLayout = JSON.parse(JSON.stringify(this.state.myLayout));
newLayout.x += 2;

<ReactGridLayout
    layout={newLayout}
>
    {children}
</ReactGridLayout>

Now everything works as expected :)

nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue May 8, 2017
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
nikolas added a commit to nikolas/react-grid-layout that referenced this issue Sep 20, 2017
This should solve this problem:
react-grid-layout#382

But may have unwanted side effects if you're relying on the global
`layout` array.
@stclairdaniel
Copy link

@developer94404 Thank you so much. This was driving me batty and your solution worked perfectly.

@vijaygawade18
Copy link

@pkerpedjiev Thanks for the solution on layout change.

nikolas added a commit to ccnmtl/react-grid-layout that referenced this issue May 23, 2018
@nikolas
Copy link
Contributor

nikolas commented May 23, 2018

Thanks @developer94404 - it looks like passing in the layout to ReactGridLayout as well as specifying the data-grid on individual items does solve this problem. I was only using the data-grid method up until now. Maybe we should document to help out anyone else running into this problem.

@natembennett
Copy link

natembennett commented Mar 20, 2019

@developer94404's solution worked for me, but just to simplify it for anyone who wanders on this thread (as I imagine this is a pretty integral issue for a lot of projects).

Example 1 - Does not work.

        return (
            <ReactGridLayout
                layout={this.props.layout}
                >
            </ReactGridLayout>
        )

Example 2 - Works.

        let layout = JSON.parse(JSON.stringify(this.props.layout));
        return (
            <ReactGridLayout
                layout={layout}
                >
            </ReactGridLayout>
        )

@fabik111
Copy link

@AbsohAbsoh's solution works!!!!!! I've tried to add a button that restore original dimensions of resized elements: dimensions were updated but elements were not compacted. After I've applied AbsohAbsoh's solution all works fine.
My restore function:

const layout = this.state.layout;
layout[indexmyelem].w = originawidth;
const jsonfiylayout = JSON.parse(JSON.stringify(layout));
this.setState({ 'layout': jsonfiylayout }); 

Definition of my render:

<ReactGridLayout
                layout={this.state.layout}
                >
            </ReactGridLayout>

@nitesh619
Copy link

To end the story, please use both "layouts" and "data-grid" props.

@github-actions
Copy link

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

@github-actions github-actions bot added the stale The label to apply when a pull request or an issue is stale label Oct 12, 2019
@mateja176
Copy link

The proposed solution isn't working anymore and even if it were working it is a hack for something seemingly simple. Nevertheless, I cannot say with certainty whether it is difficult to implement. However, based on how long the issue was open for, I'd say that it is. Hence, it'd be great if someone could share with us the reason why it is difficult to implement.

@jmtimko5
Copy link

jmtimko5 commented Sep 24, 2020

I am also seeing this issue. I am controlling my layout via parent component state (for undo redo of dashboard history) and using the data-grid property on each grid item. The props being passed to the grid item are indeed changing but the layout does not update.

Update:
Specifying the data-grid properties on children appears to no work, but using both layout and data-grid, or just layout does work

@molecule
Copy link

Wow thank goodness for this thread. Yes I also needed to have both layout and grid-item for changes to trigger a re-render properly. I really think this should be explained in the docs. I'll create a PR for that soon.

@nghenzi
Copy link

nghenzi commented Oct 17, 2020

I am using the answer in this stackoverflow question to resize programatically the layout and it works.

https://stackoverflow.com/questions/35689302/programmatically-change-height-width-of-items-in-react-grid-layout

@luisiacc
Copy link

Reading all of this way too late, the important thing is to always generate a new layout item reference, so this would also work:

let layout = this.props.layout.map(item => ({...item}));
return (
    <ReactGridLayout layout={layout}>{children}</ReactGridLayout>
)

@MarcBollmann
Copy link

MarcBollmann commented Oct 30, 2021

Also for working for me use: layout and data-grid both if you want to rerender correctly.
And remember to set the key property also in the layout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale The label to apply when a pull request or an issue is stale
Projects
None yet
Development

No branches or pull requests