I am making React Material-UI react-beautiful-dnd component which display number of TV breaks (each break is in a separate panel/dnd droppable) and each TV break displays the list of ads inside the break. My most minimal code is this:
import React, { useState } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import { Paper, List, ListItem, ListItemText, Box, Typography } from '@mui/material';
// Initial ads data
const initialAds = [
{ itemNo: 1, breakNum: 1 },
{ itemNo: 2, breakNum: 1 },
{ itemNo: 3, breakNum: 2 },
{ itemNo: 4, breakNum: 2 },
{ itemNo: 5, breakNum: 3 },
{ itemNo: 6, breakNum: 3 },
{ itemNo: 7, breakNum: 4 },
{ itemNo: 8, breakNum: 4 },
{ itemNo: 9, breakNum: 5 },
{ itemNo: 10, breakNum: 5 }
];
const MinimalDragDrop = () => {
const [ads, setAds] = useState(initialAds);
const onDragEnd = (result) => {
const { source, destination } = result;
// Dropped outside the list
if (!destination) {
return;
}
// Dropped in the same place
if (
source.droppableId === destination.droppableId &&
source.index === destination.index
) {
return;
}
// Find the ad being moved
const draggedAd = ads.find(ad => ad.itemNo === parseInt(result.draggableId));
// Update the breakNum of the dragged ad
const updatedAds = ads.map(ad =>
ad.itemNo === draggedAd.itemNo
? { ...ad, breakNum: parseInt(destination.droppableId.split('_')[1]) }
: ad
);
setAds(updatedAds);
};
const renderPanel = (breakNum) => {
return (
<Box key={breakNum} display="flex" flexDirection="column" alignItems="flex-start" padding="0.5rem" margin="0.5rem" border="1px solid lightgray" width="200px">
<Typography variant="body1" style={{ fontSize: '0.8rem', fontWeight: 'bold' }}>
Break {breakNum}
</Typography>
<Droppable droppableId={`panel_${breakNum}`}>
{(provided) => (
<List {...provided.droppableProps} ref={provided.innerRef} style={{ maxHeight: 150, overflow: 'auto', padding: '0.5rem' }}>
{ads
.filter(ad => ad.breakNum === breakNum)
.map((ad, index) => (
<Draggable key={ad.itemNo} draggableId={ad.itemNo.toString()} index={index}>
{(provided) => (
<ListItem
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{ ...provided.draggableProps.style, fontSize: '0.6rem', padding: '0.2rem', margin: '0px' }}
>
<ListItemText primary={`Ad ${ad.itemNo}`} primaryTypographyProps={{ style: { fontSize: '0.7rem' } }} />
</ListItem>
)}
</Draggable>
))}
{provided.placeholder}
</List>
)}
</Droppable>
</Box>
);
};
return (
<DragDropContext onDragEnd={onDragEnd}>
<Paper style={{ padding: '1rem', display: 'flex', justifyContent: 'center', flexWrap: 'wrap' }}>
{renderPanel(1)}
{renderPanel(2)}
{renderPanel(3)}
{renderPanel(4)}
{renderPanel(5)}
</Paper>
</DragDropContext>
);
};
export default MinimalDragDrop;
It is quite conscise: Droppable
panel has droppableId
, the draggable div
has draggableId
and onDragEnd
receives as arguments source and destination Droppable
with their id’s and the draggableId
. If I am assigning semantical droppablId
and draggableId
, then I can immediatly do the data update inside onDragEnd
which I am doing in this example.
This is minimal example. But my full code contains Redux store/RTK Toolkit/slice and approximately 200+ breaks (hence Droppable
panels). And I am doing the the observation of render with Firefox Web Developer Tools and Compontes/Performance tools from React Developer Tools and I can observer that just the touching and dragging the item makes re-render almost all of breaks although dragging visually encouters just two breaks/panels/Droppables
– soure and destination and I am choosing the neighbour panels for my initial tests.
So – is react-beautiful-dnd suitable for 200+ Droppable
panels in one DragDropContext
and are there mechanisms, prevention of rerender of remaining Droppable
panels if I am just dragging from one to another neighbouring panels?
Practically touching/dragging (getting grabbed) item takes around full second in the production implementationa and that is lot of time – DD is supposed to be done at the parts of seconds.
I am trying to reason how the react-beautiful-dnd may handle all this and I have no idea about basic. Maybe HTML/DOM has in-built DD features and the item (e.g. DOM element div
, etc.) can be visually captured and dragged already at the HTML/DOM level and react-beautiful-dnd should do just accounting. But may be possible as well that HTML/DOM has no DD support and that is why react-beautiful-dnd may be responsibl for all the visualization of the moving HTML/DOM element? And – in this latter case – the many, many React re-renders may be involved.