Hi, I am rather new to React as a whole, so if this issue is off-base or needs clarification please don't hesitate.
I am seeing an issue where I define a child component and try to instantiate it through the standard React constructor as seen below. "tile_info" is an object retrieved from a server which you can assume contains attributes seen in TilePanel
<ReactGridLayout
ref="rgl"
{...this.props}
layout={this.props.layout}>
<TilePanel tile={this.props.tile_info} grid={this.generateGrid()}
</ReactGridLayout>
var TilePanel = React.createClass({
render: function () {
return (
<div key={this.props.tile.title} class="widget-number" data-grid ={this.props.grid} >
<h1 className="title">{this.props.tile.title}</h1>
<h2 className="value">{this.props.tile.value}</h2>
<p style={styles.last_updated}>{this.props.tile.last_update}</p>
</div>
)
}
});
The resulting HTML for that GridItem does not contain the expected class/style attributes.
Expected:
<div class="react-grid-item widget-number cssTransforms react-resizable" style="width: 270px; height: 310px; position: absolute; touch-action: none; transform: translate(10px, 10px);">
Actual:
<div class="widget-number" style="background-color:#ff9618;" data-reactid=".0.1.0.1.0:$/=1$daily_revenue">
Notice the lack of props on the class and style attributes.
If this isn't clear, I will do my best to clarify
Yes - if you pass a custom component, be sure to take in a style and className prop, because RGL cannot force you to render it. You need to add className={'widget-number ' + this.props.className} style={this.props.style} to the main <div>.
If you need the resize handle as well, make sure to render the children in your TilePanel Component
@STRML thanks for the clarification, that makes sense and solves most of the problem
As @larrydahooster pointed out, this doesn't render the resize handle.
I'm not quite sure what you mean when you say "make sure to render the children". Is this demonstrated in on ef the examples by chance?
did you try:
var TilePanel = React.createClass({
render: function () {
return (
<div key={this.props.tile.title} class="widget-number" data-grid ={this.props.grid} >
{this.props.children}
<h1 className="title">{this.props.tile.title}</h1>
<h2 className="value">{this.props.tile.value}</h2>
<p style={styles.last_updated}>{this.props.tile.last_update}</p>
</div>
)
}
});
I encountered the same issue. I think it is worth adding to the README.
By the way , one possible solution is to make a ReactGridLayout wrapper which wraps it's children with a
Or even better, add to the ReactGridLayout a property for an item wrapper element and make it a div by default. That way people won't encounter the problem of not having GridItems properties, and if people want no wrapper they can set the wrapper property to null.
The implementation would be to go over the children and wrap them like this
<div key=child.key>{child}</div>
It is not perfect since, someone might don't want a wrapper, or they want to put their own stuff on the grid-item element.
Maybe a better solution would be to have an AbstractGridItem component, and require all children to extend it.
I don't know....
But I think this issue should be clear in the README, since it is a bit hard to debug and find out what is happening. Weird things happen when I use a custom component as a child of ReactGridLayout.
Did anyone find a solution to this? I considered this to be no-brainer, just add my own Component as a child of ReactGridLayout and it would work, but then it went all crazy. Now I'm not sure - is it supported, or we should only use 'div' as a grid item? If so, how can we manage different types of tiles, refer to GridItem properties (for example I'd like to decide what image ratio to display in a grid item based on width and height of that grid item). How can I achieve it only using
inside? Or I could doYes there's a pull request by cninden that fixes it
On Aug 18, 2016, at 8:27 AM, hepiyellow [email protected] wrote:
Or even better, add to the ReactGridLayout a property for an item wrapper element and make it a div by default. That way people won't encounter the problem of not having GridItems properties, and if people want no wrapper they can set the wrapper property to null.
The implementation would be to go over the children and wrap them like this
{child}It is not perfect since, someone might don't want a wrapper, or they want to put their own stuff on the grid-item element.
Maybe a better solution would be to have an AbstractGridItem component, and require all children to extend it.
I don't know....
But I think this issue should be clear in the README, since it is a bit hard to debug and find out what is happening. Weird things happen when I use a custom component as a child of ReactGridLayout.—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
You have to use a component that will accept a few properties, namely style and className.
@nitronick600 I see no such pull request - on which repository?
I tried passing these props, but I only managed to get resizing working, but not dragging of tiles. If anyone has full working code snippet together with configuring grid-layout component, I'd be really thankful. For now I had no idea how to fix this and I started thinking about just doing it with 'divs' and using callbacks + list of tiles contained in state that will hold all needed information and react to resizing/dragging.
I am mistaken, I was thinking about the drag and drop issue.
I'm seeing the same issue as @noizex where resizing works, but dragging does not work with a custom component. Any ideas on this @STRML, @nitronick600, @hepiyellow, @larrydahooster ?
@noizex - fwiw, I was able to work around this issue by wrapping my custom component with a div. Working code:
<div key={i} data-grid={{w: 2, h: 3, x: 0, y: 0}}>
<CustomComponent title={l.header.title}/>
</div>
I've spent 3 hours trying to figure out why my custom component doesn't work until I've found this thread. It should be added to README.
Adding className={'widget-number ' + this.props.className} style={this.props.style} to the main <div> of the custom component doesn't work. Adding {...this.props} works... kind of. Dragging the components is laggy and the resize handle is not there. @STRML has something changed in RGL since your last answer?
Adding summary of what I've found, I feel like I have a good understanding of this issue
Follow the code from ReactGridLayout to GridItem, then through Griditem.mixinDraggable to DraggableCore and Griditem.mixinResizable to Resizeable. This will show you exactly everything that needs to be passed down and also hopefully convince you to not bother. As others mentioned previously, you need to pass the className and style props. You also need to pass the children props if you're using resize. You also need to pass 4 different event handlers for draggability. @DanielRoeven 's comment on passing {...this.props} seeks to blanket solve it, but this omits the necessity to pass down the children, which is why he doesn't see the resize handle (a child).
Yes, you could get it working correctly with {...this.props} (or manually passing the ones you need, which I made work too) and passing the children down. But don't. You're exposing too many assumptions about how react-grid-layout, react-draggable, and react-resizable work - particularly parts of them that might forget to consider an "involved" use case like this if updated.
I'd also be mindful wrapping your component in a div. You're still probably going to need to do some things like add styles to the "real" div that RGL uses. I wanted to use my own component to keep my code more organized, and this approach (which I also tried) caused me to split out my styles, and created some temporary bugs out of confusion.
You could also create a "faux" component - a vanilla function that returns a real component. This allowed me to keep all my "Widget" component info in one file and my "Dashboard" kinds of things in another file.
eg.
const buildWidget = function(layoutRow) {
return (
<div className="widget" key={layoutRow.i}>
<WidgetContent />
</div>
)
};
However I think that design might have negative repercussions later that I haven't seen yet.
Anyways, I'd agree there ought to be some authoritative info about this in the README or some updates to allow better support here, seems like this is a common use case.
Still no solution to make a custom component resizeable without putting it in a div wrapper?
No, your custom component must accept style and className props or it
will not work.
On Sep 10, 2017 6:54 PM, "MaxHogervorst" notifications@github.com wrote:
Still no solution to make a custom component resizeable without putting it
in a div wrapper?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/STRML/react-grid-layout/issues/299#issuecomment-328383037,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABJFP9ngJhmS4P1FlDTdOih33ByfMMfWks5shHaygaJpZM4JWWqV
.
I've tried all of the suggestions above and it's not working for me. I don't know if this was working at one time but now it's broken. https://stackblitz.com/edit/react-rncnqr
<ResponsiveGridLayout
layouts={this.state.layouts}
autoSize={autosize}
breakpoints={breakpoints}
cols={cols}
margin={margin}
onLayoutChange={(layout, newLayout) => this.onLayoutChange(layout, newLayout)}>
// this works
<div key="1">...</div>
// the following doesn't work
<CustomCharts
{...this.props}
className={'widget-number ' + this.props.className}
style={this.props.style} />
</ResponsiveGridLayout>
@STRML I updated my stackblitz example and it still doesn't work.
Thanks @STRML, I'm guessing there isn't a way to have a custom component contain multiple boxes though? I ended up with a solution based on how you used generateDOM() in some of your examples. Either way I appreciate the sample, this helps a lot!
When I add the style and className to my custom component, the drag handle doesn't work. Did anyone got it working? I can't just do {...this.props} I'm using typescript and it becomes a mess. Is there anything specific I'm supposed to do?
Edit
I found out that in the wrapped component, for the drag handle to work as expected you also need to provide (in addition to style and className) the following event handlers: onMouseUp, onMouseDown, onTouchStart, onTouchEnd.
So your custom component would look something like:
function MyComponent(props) {
return (
<div
style={{ ...props.style }}
className={"my-component " + props.className}
onMouseUp={props.onMouseUp}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}
onTouchEnd={props.onTouchEnd}
>
{props.children}
</div>
);
}
You also need to pass props.children so that the resize handle will be rendered as expected.
The trick is to set className to wrapper instead of widget-number
❌ <div {...this.props} className={`widget-number ${this.props.className}`}>
✅ <div {...this.props} className={`wrapper ${this.props.className}`}>
Most helpful comment
Adding summary of what I've found, I feel like I have a good understanding of this issue
Explanation
Follow the code from ReactGridLayout to GridItem, then through Griditem.mixinDraggable to DraggableCore and Griditem.mixinResizable to Resizeable. This will show you exactly everything that needs to be passed down and also hopefully convince you to not bother. As others mentioned previously, you need to pass the className and style props. You also need to pass the children props if you're using resize. You also need to pass 4 different event handlers for draggability. @DanielRoeven 's comment on passing
{...this.props}seeks to blanket solve it, but this omits the necessity to pass down the children, which is why he doesn't see the resize handle (a child).Solutions
Yes, you could get it working correctly with {...this.props} (or manually passing the ones you need, which I made work too) and passing the children down. But don't. You're exposing too many assumptions about how react-grid-layout, react-draggable, and react-resizable work - particularly parts of them that might forget to consider an "involved" use case like this if updated.
I'd also be mindful wrapping your component in a div. You're still probably going to need to do some things like add styles to the "real" div that RGL uses. I wanted to use my own component to keep my code more organized, and this approach (which I also tried) caused me to split out my styles, and created some temporary bugs out of confusion.
You could also create a "faux" component - a vanilla function that returns a real component. This allowed me to keep all my "Widget" component info in one file and my "Dashboard" kinds of things in another file.
eg.
However I think that design might have negative repercussions later that I haven't seen yet.
Anyways, I'd agree there ought to be some authoritative info about this in the README or some updates to allow better support here, seems like this is a common use case.