-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MultiGrid (with rowHeight and columnWidth functions) resizing #552
Conversation
}) | ||
this._bottomRightGrid && this._bottomRightGrid.measureAllCells({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duh, this was a stupid typo on my part. Apologies.
fixedColumnCount !== nextProps.fixedColumnCount | ||
) { | ||
this._leftGridWidth = null | ||
} | ||
|
||
if ( | ||
fixedRowCount !== nextProps.fixedRowCount || | ||
rowHeight !== nextProps.rowHeight | ||
rowHeight instanceof Function || rowHeight !== nextProps.rowHeight |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous behavior here was intentional. If a function prop is passed, Grid
(and so MultiGrid
) don't assume they can detect when it has changed. That's because (a) things outside of the function may invalidate the size without the function prop itself changing and (b) people often define inline props like so: rowHeight={(index) => blah}
which will recreate on each render. Invalidating cache is expensive so this is an intentional optimization. If a user uses a function prop, he should manually clear the cache.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense on the optimization. By what method should the cache be cleared?
Perhaps a new public method like:
clearCachedStyles() {
this._topGridHeight = null;
this._leftGridWidth = null;
this._maybeCalculateCachedStyles(null, this.props)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Users should call recomputeGridSize
if something has happened to invalid one or more columns/rows. Grid
then resets its own cache when recomputeGridSize
is called.
That being said, I see your point that nothing inside of MultiGrid
currently resets _leftGridWidth
or _topGridHeight
. I think MultiGrid
should follow the precedent in Grid
and reset it in recomputeGridSize
.
@@ -366,6 +369,8 @@ export default class MultiGrid extends Component { | |||
left: 0, | |||
outline: 0, | |||
overflow: 'hidden', | |||
overflowX: 'hidden', | |||
overflowY: 'hidden', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are the long-form props needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they are needed to counteract gridStyle.overflowX and gridStyle.overflowY being set in
https://github.com/bvaughn/react-virtualized/blob/master/source/Grid/Grid.js#L566
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Roger that. We should go ahead and get rid of the short-hand form (overflow
) then. It's totally redundant.
} | ||
}))) | ||
|
||
multiGrid.recomputeGridSize() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the purpose of this test. Could you explain what it's testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I first switched the measureAllCells calls to recomputeGridSize, negative values were getting passed as column and row indexes, which would throw an error. This was my (poor) failing test prior to adding the comparison against the fixed row/col sizes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what else to explicitly assert, but at least I can add expect(...).not.toThrowError(...);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. I see.
expect(...).not.toThrowError(...)
is kind of the default behavior of any testing framework though so probably not worth explicitly adding.
Perhaps I was just confused by the name of this test. What makes it different than this one for instance. You could update it to say something about recomputeGridSize
specifically, since that's what it's testing, but I wonder if we couldn't do 1 better than that and assert that it actually recomputes the inner Grid
sizes (and resets _leftGridWidth
and _topGridHeight
like we chatted about above)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking the same thing this morning, I'll see what I can whip up.
Function props like |
Sorry, I didn't explain the setup well. Nothing wrong with AutoSizer, I just wanted to explain my usage since I didn't have a stand-alone test case to show.
|
Thank you for clarifying! I understand now. 😁 I think this is actually caused by a combination of the typo you fixed here and what I mentioned in this comment. Thanks for taking the time to submit this PR too! Couple of minor changes and I think it will be good to merge! |
recomputeGridSize should be manually called by a user if rowHeight and/or columnWidth values are invalidated by something outside of the functions (e.g. a window resize)
@bvaughn I think I've got a much better test now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test does look much better. Thank you!
One small change requested but otherwise looks great!
columnIndex, | ||
rowIndex: rowIndex - fixedRowCount | ||
const col = (columnIndex >= fixedColumnCount ? columnIndex - fixedColumnCount : columnIndex) | ||
const row = (rowIndex >= fixedRowCount ? rowIndex - fixedRowCount : rowIndex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, just noticed these 2 lines. This change doesn't look right. I believe these 2 lines should be reverted to the way it was before but with your correction of my recomputeGridSize
typo 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without that guard, I get:
TypeError: Cannot read property 'offset' of undefined
at CellSizeAndPositionManager.getVisibleCellRange (CellSizeAndPositionManager.js:184)
at ScalingCellSizeAndPositionManager.getVisibleCellRange (ScalingCellSizeAndPositionManager.js:150)
at Grid._calculateChildrenToRender (Grid.js:544)
at Grid.componentWillUpdate (Grid.js:428)
at ReactCompositeComponent.js:711
at measureLifeCyclePerf (ReactCompositeComponent.js:75)
at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:710)
at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:645)
at ReactCompositeComponentWrapper.receiveComponent (ReactCompositeComponent.js:547)
at Object.receiveComponent (ReactReconciler.js:125)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of dealing with it in MultiGrid, perhaps a change to CellSizeAndPositionManager#resetCell instead?
resetCell (index: number): void {
let guarded = Math.max(index, 0)
this._lastMeasuredIndex = Math.min(this._lastMeasuredIndex, guarded - 1)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, fair enough. I think the correct fix is to add a Math.max(0, maybeNegativeIndex)
in MultiGrid
so that it doesn't pass negative values. As it is (with this change) we may skip cells in the bottom and/or right grids if indices > 0 and < fixed-count are passed.
@@ -380,7 +387,8 @@ export default class MultiGrid extends Component { | |||
this._topRightGridStyle = { | |||
left: this._getLeftGridWidth(props), | |||
outline: 0, | |||
overflow: 'hidden', | |||
overflowX: 'hidden', | |||
overflowY: 'hidden', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good fix 👍
I've merged your PR locally, after fixing that one small issue. Thanks so much, again! |
Not sure why Github still thinks the PR is open. You can see that it's been merged here. Oh well. 😁 |
Released with 8.11.3 Gave you credit for this fix in the changelog |
For a MultiGrid (wrapped by an AutoSizer) with rowHeight and columnWidth functions, grid sizes are not recalculated after window resizing. I attached an onResize function to the AutoSizer to explicitly force it via calling MultiGrid.recomputeGridSize(). In the course of debugging that, I encountered these 3 bugs.
Even after calling recomputeGridSize with these fixes, I still needed to call _maybeCalculateCachedStyles, but I wan't sure if that should always occur in the recomputeGridSize call or not.