React-grid-layout: Grid Tiles are moving on first render although useCSSTransforms=false

Created on 14 Apr 2016  路  12Comments  路  Source: STRML/react-grid-layout

I am facing an issue right now with react-grid-layout cause I need to initially render it without any movement. Just the static grid with no pop-out effect. So i set useCSSTransforms=false and the pop-out effect was gone. But then I recognized that the tiles are slightly moving on initial render. This is caused by this css-style:

.react-grid-item {
  transition: all 200ms ease;
  transition-property: left, top;
}

I recorded some screencaps of how it looks. NOTE: For visualization purposes I set the transition time to 2000ms instead of 200ms!

This is how the grid behaves in my app when it is initially rendered or reloaded. The movement of the tiles looks disrupted. With a transition-time of 200ms it looks like it is jumping some pixels.
usecasetransition

The next screencap is taken from the 'React-Grid-Layout Dev Demo' (npm run git) with useCSSTransforms=false and also transition set to 2000ms
initiallyloadingdemotransition

And this is the same demo with the desired behavior, simply achieved with useCSSTransforms=false and removed transition styles
initiallyloadingdemonotransition

But quickly I realized that when I removed the transition styles, all the benefits of them were gone too. No slighlty moving tiles on window resize and also no snapping of the tiles to its destination on drop.

Two more demos to show the drag and drop behavior with and without transition styles:
Desired behavior with transitions (200ms this time)
41

behavior with transitions disabled
42

I think to achieve a grid that is statically rendered when useCSSTransforms=false but keeps its transition effects, the transition-style has to be added after the grid is initially rendered for the first time. How do you think about it? I would do the refactor if there is a chance to get it merged into this repo.

Most helpful comment

If you'd like to eliminate that animation as well, set measureBeforeMount={true} on the wrapped component. It will render an empty div with the same props as RGL, measure it, _then_ actually render RGL after it has the accurate width.

Could someone give an example of this? I am not sure how to properly pass that prop onto the wrapped component, even after reading much documentation. I've tried various option of passing props to HOCs to no avail.

All 12 comments

Thanks for this very detailed ticket.

I'm working on this issue now.

The new default behavior in 0.12.0 is to eliminate as much of this animation as possible. However, if you are using WidthProvider, the following sequence will take place:

  • RGL is mounted with a default width of 1280.
  • WidthProvider fires componentDidMount, which measures the actual size now that we have a DOM reference.
  • RGL is re-rendered with the actual width, which causes a slight animation.

If you'd like to eliminate that animation as well, set measureBeforeMount={true} on the wrapped component. It will render an empty div with the same props as RGL, measure it, _then_ actually render RGL after it has the accurate width.

:clap:

Hey, thanks a lot for that quick fix. Works like a charm, I am really impressed!

馃挴 Great

@STRML Hey, one thing I did not saw at the first try is that it throws warnings when an old Grid gets unmounted and a new one gets mounted.

'Uncaught Invariant Violation: findDOMNode was called on an unmounted component.' Doing some further investigations later on.

That's odd. If that's the findDOMNode call in onWindowResize(), there shouldn't be any way for that to fire while unmounted.

Hey, I just wanted to let you know that I created my own customWidthProvider which uses https://github.com/ctrlplusb/react-sizeme, a pretty nice size Provider. It worked out of the box. I do not know if it is an option for you to use it, but maybe you like to take a look at it.

import React, { Component } from 'react';
import sizeMe from 'react-sizeme';

const sizeMeHOC = sizeMe({
   monitorWidth: true,
   refreshRate: 16
});

export default (ComposedComponent) => sizeMeHOC(class extends Component {
   render() {
       const { width } = this.props.size;
       return <ComposedComponent {...this.props} width={width} {...this.state} />;
   }
}
);

That's a pretty nice HOC, @larrydahooster. I'm not sure if it makes sense to include as a dep, but I'm happy to link it in the <WidthProvider> docs as an alternative.

If you'd like to eliminate that animation as well, set measureBeforeMount={true} on the wrapped component. It will render an empty div with the same props as RGL, measure it, _then_ actually render RGL after it has the accurate width.

Could someone give an example of this? I am not sure how to properly pass that prop onto the wrapped component, even after reading much documentation. I've tried various option of passing props to HOCs to no avail.

For anyone else who came here looking for an example of measureBeforeMount, I found a decent example here: https://github.com/STRML/react-grid-layout/blob/3352c84515e587c2bb7ec7935e24be5705d33704/test/examples/14-toolbox.jsx

Just a heads up, by using measureBeforeMount it will ignore the width of the sidebar if there was.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

moritzschaefer picture moritzschaefer  路  3Comments

ierhyna picture ierhyna  路  3Comments

daumann picture daumann  路  3Comments

MaksZhukov picture MaksZhukov  路  3Comments

sasha240100 picture sasha240100  路  3Comments