React-grid-layout: Won't work on nested/reusable components?

Created on 3 Nov 2016  路  13Comments  路  Source: STRML/react-grid-layout

Hi, great work on this plugin.

I have reusable components for most (if not all) html elements, when I try to align with react-grid-layout they don't work.

They don't follow any of the layout, margin props which makes it really hard to deal with.

However, when i switch to normal html elements react-grid-layout works.

Here is an example.

//- Say, this is my nav-bar component.
export default class Nav extends Component {
    render() {

    var layout = [
            {i: 'a', x: 0, y: 0, w: 1, h: 2, static: true},
            {i: 'b', x: 2, y: 0, w: 1, h: 2, static: true},
            {i: 'c', x: 4, y: 0, w: 1, h: 2, static: true},
            {i: 'd', x: 6, y: 0, w: 1, h: 2, static: true},
            {i: 'e', x: 8, y: 0, w: 1, h: 2, static: true}
        ];

        return (

            <ReactGridLayout className="layout" layout={layout} cols={12} rowHeight={30} width={1200} margin={[1, 1]} >
                <Div divStyle="navItem" key="a" href="/">
                    Home
                </Div>
                <Div divStyle="navItem" key="b" href="blog">
                    Blog
                </Div>
                <Div divStyle="navItem" key="c" href="about">
                    About
                </Div>
                <Div divStyle="navItem" key="d" href="media">
                    Media
                </Div>
                <Div divStyle="navItem" key="e" href="contact">
                    Contacts
                </Div>

            </ReactGridLayout>
        )
    };
}

//- And this is the Div component that wraps the html <div> element and adds some styles
//- with react-css-modules.
@CSSModules(styles)
class Div extends Component {

    render() {

        return (

            <div styleName={this.props.divStyle} >
                <a href={this.props.href}> {this.props.children} </a>
            </div>
        );
    }
}

Here is a screenshot of this approach.
windowed_2016-11-03_21h43s43

As you can see, it completely ignored most (if not all) of the props i passed here

<ReactGridLayout className="layout" layout={layout} cols={12} rowHeight={30} width={1200} margin={[1, 1]} >

which includes the layout array that had x: n .

Here is a link to the project.

stale

Most helpful comment

Here we go:

  1. Do not define draggableHandle prop

  2. In your GridCell's render:

const {
  style,
} = this.props;
const propsToPassToDragHandle = _.pick(this.props, ['onMouseDown', 'onMouseUp', 'onTouchStart', 'onTouchEnd']);
return (
  <div
    style={{
      background: '#ccc',
      ...style,
    }}
  >
    <div
      style={{
        width: 20,
        height: 20,
        background: 'red',
        position: 'absolute',
        top: 5,
        right: 5,
      }}
      {...propsToPassToDragHandle}
    />
      {/* more content */}
   </div>
);

This gives you the following cells with only red squares working as handlers.
capture

What is cool is that the offset does not even get broken when you start to drag!

The only thing left to sort out is z-index while dragging.

All 13 comments

Yes - your custom components must be able to receive a style prop.

@STRML I'm sorry, what do you mean my

custom components must be able to receive a style prop

What contents should the style prop have so as to play well with react-grid-layout?

I don't quite understand you sir.

As in, your custom component must be able to receive a style prop and pass it on to an actual DOM element. That's how RGL places elements in the grid.

Thanks STRML, I've had the same issue, however I should note that in my case I needed to pass all the props to the child DIV, not only the style.

Also, I still have issues with the draggable handler not being addedwhen the element is contained in a Redux Connect element.

Some other things to be aware of when using a non DOM element in the grid?

@madarco I also have an array of connected child components inside ReactGridLayout and so draggableHandle is ignored. Have you found a solution for this redux-related case by a chance?

Here we go:

  1. Do not define draggableHandle prop

  2. In your GridCell's render:

const {
  style,
} = this.props;
const propsToPassToDragHandle = _.pick(this.props, ['onMouseDown', 'onMouseUp', 'onTouchStart', 'onTouchEnd']);
return (
  <div
    style={{
      background: '#ccc',
      ...style,
    }}
  >
    <div
      style={{
        width: 20,
        height: 20,
        background: 'red',
        position: 'absolute',
        top: 5,
        right: 5,
      }}
      {...propsToPassToDragHandle}
    />
      {/* more content */}
   </div>
);

This gives you the following cells with only red squares working as handlers.
capture

What is cool is that the offset does not even get broken when you start to drag!

The only thing left to sort out is z-index while dragging.

@kachkaev really interesting approach!

I had some limited results by passing all the ...props to my child elements, however in the end I've found a simpler solution:

I've created a new react component that takes all the children, encapsulate them in a div, and then put them in our ReactGridLayout.
In this way I use this new component in place of the ReactGridLayout and all the elements will have the resize handle.

```javascript
//Add a div around each component:
childrenDivs = [];
for (let c = 0; c < children.length; c++) {
let key = children[c].key ? children[c].key : c;
childrenDivs.push(

)
}

return (
{ childrenDivs }

);
```

In my testing I found out that is compulsory to pass both style and className properties to the React components being layouted by ReactGridLayout

 <ReactGridLayout className="layout" layout={layout} cols={3} rowHeight={50}
                         width={1200}>
          <SimpleTile key="tile-1">1</SimpleTile>
          <SimpleTile key="tile-2">2</SimpleTile>
          <SimpleTile key="tile-3">3</SimpleTile>
          <SimpleTile key="tile-4">4</SimpleTile>
          <SimpleTile key="tile-5">5</SimpleTile>
          <SimpleTile key="tile-6">6</SimpleTile>
          <SimpleTile key="tile-7">7</SimpleTile>
          <SimpleTile key="tile-8">8</SimpleTile>
          <SimpleTile key="tile-9">9</SimpleTile>
        </ReactGridLayout>

Listing of SimpleTile, notice passed values for className and style

import React, {Component, PropTypes} from 'react'

class SimpleTile extends React.Component {

  render() {
    return <div key="{this.props.key}" className={this.props.className} style={this.props.style}>
      {this.props.children}
    </div>;
  }
}

export default SimpleTile

After making this work, I think it looks alright. I guess the only thing that needs to be done is to document this on a highly visible / easily findable place.

Thanks for posting your findings!

I still don't understand how to do this. Clear docs on this would be amazing. I'm trying to include custom components via styled-jsx.

From the example above posted from JabbyPanda, SimpleTile should add the following props to the root element.

  const propsToPassToDragHandle = _.pick(this.props, ['onMouseDown', 'onMouseUp', 'onTouchStart', 'onTouchEnd']);
  return <div {...propsToPassToDragHandle}>{stuff}</div>

Eh.. I just ended up wrapping the custom component in a <div key={a}>. Seems to work fine.

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

Was this page helpful?
0 / 5 - 0 ratings