perf(virtualized-lists) removing rerender cells for every change of Virtualized list (#46103)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/46103

Reducing the boundary of rerender of virtual lists. Previously with prop: "strictMode={true}" the VirtualizedList still re rendered each CellRenderer component. Because method getDerivedStateFromProps generated every time a new uniq state and the cells didn’t have a PureComponent. It helps to improve react performance for lists which have 5+ elements.

I reused recomended approach from react doc https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization

changelog: [internal]
Optimizing CellRenderer of VirtualizedList

Reviewed By: NickGerleman, sammy-SC

Differential Revision: D61493434

fbshipit-source-id: 917a33e48bd2f18e8ac150e5701d2e7c45dbe879
This commit is contained in:
Andrei Marchenko
2024-08-21 14:23:07 -07:00
committed by Facebook GitHub Bot
parent 9239ad1c6b
commit 954e294183
3 changed files with 32 additions and 8 deletions
@@ -270,6 +270,11 @@ const definitions: FeatureFlagDefinitions = {
description:
'Enables access to the host tree in Fabric using DOM-compatible APIs.',
},
enableOptimisedVirtualizedCells: {
defaultValue: false,
description:
'Removing unnecessary rerenders Virtualized cells after any rerenders of Virualized list. Works with strict=true option',
},
isLayoutAnimationEnabled: {
defaultValue: true,
description:
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ff51057b07601cf49603e2f28ef501b7>>
* @generated SignedSource<<4ec8afb16cae6c04f166b0c28a906aff>>
* @flow strict-local
*/
@@ -30,6 +30,7 @@ export type ReactNativeFeatureFlagsJsOnly = {
animatedShouldDebounceQueueFlush: Getter<boolean>,
animatedShouldUseSingleOp: Getter<boolean>,
enableAccessToHostTreeInFabric: Getter<boolean>,
enableOptimisedVirtualizedCells: Getter<boolean>,
isLayoutAnimationEnabled: Getter<boolean>,
shouldSkipStateUpdatesForLoopingAnimations: Getter<boolean>,
shouldUseAnimatedObjectForTransform: Getter<boolean>,
@@ -111,6 +112,11 @@ export const animatedShouldUseSingleOp: Getter<boolean> = createJavaScriptFlagGe
*/
export const enableAccessToHostTreeInFabric: Getter<boolean> = createJavaScriptFlagGetter('enableAccessToHostTreeInFabric', false);
/**
* Removing unnecessary rerenders Virtualized cells after any rerenders of Virualized list. Works with strict=true option
*/
export const enableOptimisedVirtualizedCells: Getter<boolean> = createJavaScriptFlagGetter('enableOptimisedVirtualizedCells', false);
/**
* Function used to enable / disabled Layout Animations in React Native.
*/
@@ -8,6 +8,7 @@
* @format
*/
import * as ReactNativeFeatureFlags from '../../react-native/src/private/featureflags/ReactNativeFeatureFlags';
import type {CellRendererProps, RenderItemType} from './VirtualizedListProps';
import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
import type {
@@ -53,7 +54,7 @@ type State<ItemT> = {
...
};
export default class CellRenderer<ItemT> extends React.Component<
export default class CellRenderer<ItemT> extends React.PureComponent<
Props<ItemT>,
State<ItemT>,
> {
@@ -68,12 +69,24 @@ export default class CellRenderer<ItemT> extends React.Component<
props: Props<ItemT>,
prevState: State<ItemT>,
): ?State<ItemT> {
return {
separatorProps: {
...prevState.separatorProps,
leadingItem: props.item,
},
};
if (ReactNativeFeatureFlags.enableOptimisedVirtualizedCells()) {
if (props.item !== prevState.separatorProps.leadingItem) {
return {
separatorProps: {
...prevState.separatorProps,
leadingItem: props.item,
},
};
}
return null;
} else {
return {
separatorProps: {
...prevState.separatorProps,
leadingItem: props.item,
},
};
}
}
// TODO: consider factoring separator stuff out of VirtualizedList into FlatList since it's not