Open StephenChips opened 2 months ago
Hi, I have a similar issue.
I am using react-virtualized
and react-beautiful-dnd
in order to make a kanban board with virtualized columns.
The issue that I'm encountering is that the row measurements are not always correct, even if I set defaultHeight
to something bigger than 0 (if I set it to 0, the heights don't get calculated correctly, as @StephenChips said).
Here's a video of the issue: https://github.com/bvaughn/react-virtualized/assets/83024157/239f86a1-a9a5-4aef-9ea7-7d5a05305401
As you can see, at the start, the heights are calculated correctly, but sometimes the cards overlap each other.
I checked if this was an issue with my implementation of react-beautiful-dnd
or CellMeasurer
, but the issue seems to be that the height of the card changes even if the only thing that changes on the card is the transfrom property (caused by the dnd library), and the measured height put in the style
prop passed by the List
component is less than the actual height, causing the card under to overlap.
This is the list I use in my Column component:
const cache = new CellMeasurerCache({
defaultHeight: 250,
fixedWidth: true,
})
// Clear the cache when the filtered tickets change
useEffect(() => {
// This is needed otherwise the items height would be wrong
setTimeout(() => {
cache.clearAll()
listInstanceRef.current && listInstanceRef.current.recomputeRowHeights()
}, 0)
}, [filteredTickets])
<List
height={600} // This should be the height of the viewport
mode='virtual'
width={provided.innerRef?.current?.clientWidth || 300}
deferredMeasurementCache={cache}
rowHeight={cache.rowHeight}
rowRenderer={Row}
rowCount={itemCount}
tickets={filteredTickets}
ref={(ref) => {
// react-virtualized has no way to get the list's ref that I can so
// So we use the `ReactDOM.findDOMNode(ref)` escape hatch to get the ref
if (ref) {
// eslint-disable-next-line react/no-find-dom-node
const listRef = ReactDOM.findDOMNode(ref)
if (listRef instanceof HTMLElement) {
provided.innerRef(listRef)
}
listInstanceRef.current = ref
}
}}
/>
function Row ({ index, isScrolling, key, parent, style }) {
const tickets = parent.props.tickets
const ticket = tickets?.[index]
if (!ticket) {
console.log("Ticket doesn't exist, index: ", index)
return null
}
const patchedStyle = {
...style,
top: style.top + 7.5,
left: style.left,
height: style.height,
width: style.width,
}
return (
<CellMeasurer
cache={cache}
columnIndex={0}
key={key}
rowIndex={index}
parent={parent}
>
{({ measure, registerChild }) => {
return <Ticket
key={ticket.id}
position={index}
ticket={ticket}
style={patchedStyle}
filtered={true}
showStatus={true}
measureRef={registerChild}
measure={measure}
cache={cache}
/>
}}
</CellMeasurer>
)
}
And this is what I do in my Ticket component:
// Measure the ticket height
useEffect(() => {
if (measure) measure()
}, [measure, measureRef])
const renderTicket = (provided) => {
return (
<div
key={ticket.id}
ref={(el) => {
provided.innerRef(el)
if (measureRef) measureRef(el)
}}
className={classNames(
'kanban-board__ticket',
styles.ticket,
{
incomplete: ticket.incomplete,
'activities-completed': ticket.activities_completed,
}
)}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{
...style,
...provided.draggableProps.style,
}}
>
{/* Other code */}
</div>
)
}
if (isDragPlaceholder) {
return renderTicket(providedProp)
}
return (
<Draggable
key={ticket.id}
draggableId={ticket.id.toString()}
index={position}
isDragDisabled={false}
>
{(provided) => renderTicket(provided)}
</Draggable>
)
Am I doing something wrong, or is there something wrong with how CellMeasurer
calculates the height of the element?
Bug Report
I don't know if is a bug or it's just a misuse. If it isn't a bug, please tell me why this happens then close the issue.
Here is the codesandbox contains the code, it is also added at the end of this post:
https://codesandbox.io/p/sandbox/restless-river-5sk2s4
What is the current behavior?
I was following the instruction to write a simple
<List />
demo. The list shows some random lorem ipsum sentences and each row has fixed width and dynamic height. As shown in the guide, I should use<CellMeasurer>
andCellMeasureCache
together to figure out each row's height for thecomponent, so I did. However when I set the
defaultHeight
to0
, some rows weirdly overlap. It seems their heights were not calculated correctly.If I set the
defaultHeight
to value larget than 3 (defaultHeight > 3
), no row will overlaps anymore.What is the expected behavior?
No matter what
defaultHeight
I set, every row's height should be calculated correctly based on it's content's height and none of row should overlaps with the previous or next one.Which versions of React and react-virtualized, and which browser / OS are affected by this issue? Did this work in previous versions of react-virtualized?
The code
The overlapped columns