-
Notifications
You must be signed in to change notification settings - Fork 289
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
Performance fixes for v2.0 and fix regression with out of order columns #691
Performance fixes for v2.0 and fix regression with out of order columns #691
Conversation
'columnGroupElements', | ||
'columnElements', |
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.
state.columnProps
has been replaced with state.columnElements
.
One reason being that there's a modified version of columnProps
returned by selectors, leading to confusion between state.columnProps
and someSelector().columnProps
.
// NOTE (pradeep): This can be simplified via _.pick() | ||
// However, _.pick is much slower than the hand written version here. |
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.
for (const columnGroupReactElement of children) { | ||
const cellGroupType = getCellGroupType(columnGroupReactElement); | ||
const columnGroupProps = _extractProps(columnGroupReactElement); | ||
columnGroupProps.index = columnGroupIndex; |
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.
Also calculate and store the index while extracting the column/column-group.
columnGroupElements, | ||
columnElements, |
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.
columnGroupElements
groups column props by cellGroupType
, where as columnProps
is a flat ordered list of column prop
objects.
@@ -12,16 +12,55 @@ | |||
|
|||
'use strict'; | |||
|
|||
import reduce from 'lodash/reduce'; | |||
import { createSelector } from 'reselect'; |
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.
createSelector
is used here to memoize the selectors.
} | ||
const cacheOptions = { | ||
memoizeOptions: { | ||
maxSize: 12, // 3 cell group types * 4 template types |
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 ensures we can call the selectors for each cell group type for each template type without having to recompute the widths.
@@ -164,55 +175,18 @@ function flexWidths(columnGroupProps, columnProps, viewportWidth) { | |||
* scrollableColumns: !Array.<columnDefinition> | |||
* }} | |||
*/ | |||
function groupElements(elements) { |
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.
Besides grouping, groupElements
also assigned index
and offset
.
The extra work is no longer needed.
// if no flexGrow is specified, column defaults to original width | ||
if (!flexGrow) { | ||
return column; | ||
function flexWidths(columnGroupElements, columnElements, viewportWidth) { |
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 main change here is that the flexWidths
also calculates the offsets of the column based on the new flex width.
This was previously done by groupElements()
below.
@@ -6,6 +6,26 @@ import forEach from 'lodash/forEach'; | |||
|
|||
import convertColumnElementsToData from '../../src/helper/convertColumnElementsToData'; | |||
|
|||
function column(overrides) { |
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.
helper to create a column element
@@ -7818,7 +7818,12 @@ requires-port@^1.0.0: | |||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" | |||
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= | |||
|
|||
reselect@^4.0.0, reselect@^4.1.5: | |||
reselect@^4.0.0: | |||
version "4.1.8" |
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.
Bumped to latest version which supports cache customization for the selectors.
@@ -152,7 +152,7 @@ const slice = createSlice({ | |||
}, | |||
propChange(state, action) { | |||
const { newProps, oldProps } = action.payload; | |||
const oldState = clone(state); | |||
const oldState = clone(original(state)); |
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.
what does original do
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.
state
is proxy object from immer that points to the actual redux state.
Iterating over this proxy object is slightly slower than iterating over the original state.
original(proxyObject)
returns back the original object pointed to by the proxy.
(See original docs)
Object.freeze(state.columnElements); | ||
Object.freeze(state.columnGroupElements); | ||
Object.freeze(state.elementTemplates); | ||
|
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.
nice
}; | ||
const columnElements = getElementsContainer(); | ||
const columnGroupElements = getElementsContainer(); | ||
const elementTemplates = getElementTemplates(); |
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.
just a thought shouldnt the function name be getEmptyElementContainer/ getDefaultElementContainer
or what you have done is fine?
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.
hmm both seem fine to me, but I'll rename it to getEmptyElementsContainer
to be explicit.
LGTM |
const columnGroupElements = getElementsContainer(); | ||
const elementTemplates = getElementTemplates(); | ||
const useGroupHeader = !!( | ||
children.length && children[0].type.__TableColumnGroup__ |
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 can also be simplified by optional chaining.
const useGroupHeader = children[0]?.type.__TableColumnGroup__ ?? false
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.
done
// pre-freeze data using the freeze utility. | ||
Object.freeze(state.columnElements); | ||
Object.freeze(state.columnGroupElements); | ||
Object.freeze(state.elementTemplates); |
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.
Can convertColumnElementsToData
itself return these objects as frozen???
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.
We could, but I like to keep convertColumnElementsToData
as a pure helper method that shouldn't know about immer/parent reducer details.
will it merge to column-virtualization as well ? |
@AmanGupta2708 , yep this should be upmerged manually. |
Description
This refactors some of the code in our redux logic to improve performance for v2.
The main changes are:
state.columnProps
andstate.columnGroupProps
has been renamed tocolumnElements
andcolumnGroupElements
respectively._.pick
,_.forEach
,_.map
,_.reduce
, etc have been hand picked and replaced with faster calls (mostly native) for performance.columnWidths
selector andconvertColumnsToElements
helper have been rewritten (keeping their structure same) to make them more efficient.elementTemplates
). Luckily, we can workaround this by manually pre-freezing them shallowly.The refactor This also fixes a regression where FDT renders the wrong renderers (cell templates) when columns are specified in a different order than what gets rendered.
eg:
causes FDT to mistakenly render column C using the renderer from column B (and vice-versa).
How Has This Been Tested?
Tested on local examples.
Particularly the "Fixed Right" example which is rendered by passing columns out of order.
Types of changes
Checklist: