I'm using Material UI
with react-beautiful-dnd
to create a pretty simple Grid
column layout with elements that can be reordered. However, I'm having this jank issue with the spacing between the elements that's hard to explain, so I'll just show you a gif of it:
I'm not sure where this issue could be coming from or even what to call it. Internally, the spacing
property of Grid
is implemented using padding
, and I can't even find any information on why that wouldn't work with the drag and drop system. Here's the main part of the code:
import { makeStyles } from "@material-ui/core";
import { Grid, Paper } from "@material-ui/core";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
import { produce } from "immer";
function ReorderQuestion(props) {
const [items, setItems] = useState(props.items);
const classes = useStyles();
function onDragEnd({ source, destination }) {
if (!destination) {
return;
}
if (
destination.droppableId === source.droppableId &&
destination.index === source.index
) {
return;
}
setItems(
produce(draft => {
draft.splice(destination.index, 0, draft.splice(source.index, 1)[0]);
})
);
}
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="reorderQuestion" direction="horizontal">
{provided => (
<div {...provided.droppableProps} ref={provided.innerRef}>
<Grid spacing={3} container direction="row">
{items.map((imageSrc, index) => (
<Grid item key={imageSrc}>
<Draggable draggableId={imageSrc} index={index}>
{(provided, snapshot) => (
<Paper
innerRef={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
elevation={
snapshot.isDragging && !snapshot.isDropAnimating
? 5
: 2
}
className={classes.option}
>
<img src={imageSrc} alt="Hiking" />
</Paper>
)}
</Draggable>
</Grid>
))}
{provided.placeholder}
</Grid>
</div>
)}
</Droppable>
</DragDropContext>
);
}
const useStyles = makeStyles(theme => ({
option: {
padding: theme.spacing(2)
}
}));
Figured out the solution, thanks to @mal#8537 on the Reactiflux Discord.
The issue is that the innerRef
is being provided to the Paper
component, which doesn't actually contain the spacing - ie, it doesn't use margins. The Grid item
, its parent component, uses padding to achieve the spacing, therefore it must be moved inside the Draggable
and provided with the innerRef
(and the draggableProps
) for the spacing to be dragged along correctly.
I simply replaced the inside of items.map
with this:
<Draggable draggableId={imageSrc} index={index} key={imageSrc}>
{(provided, snapshot) => (
<Grid item
innerRef={provided.innerRef} // PROVIDE REF HERE, TO GRID
{...provided.draggableProps}>
<Paper
{...provided.dragHandleProps}
elevation={
snapshot.isDragging && !snapshot.isDropAnimating
? 5
: 2
}
className={classes.option}
>
<img src={imageSrc} alt="Hiking" />
</Paper>
</Grid>
)}
</Draggable>