Skip to content

Commit c231d5e

Browse files
genkikondofacebook-github-bot
authored andcommitted
VirtualizedList optimization - memoize FlatList._renderer
Summary: Problem: All CellRenderers rerender every time the containing VirtualizedList is rerendered. This is due to the following: - Lambda is created for each CellRenderer's onLayout prop on every VirtualizedList render (fixed in D35061321 (19cf702)) - CellRenderer's parentProps prop changes on every VirtualizedList render (fixed in D35062323 (adb2962)) - FlatList recreates renderItem/ListItemComponent in FlatList._renderer (addressed in this diff) Changelog: [Internal] - VirtualizedList optimization - memoize FlatList._renderer Reviewed By: ryancat Differential Revision: D35067472 fbshipit-source-id: 124629d94821f35b8943730839fbe72f547e80fd
1 parent adb2962 commit c231d5e

File tree

4 files changed

+34
-6
lines changed

4 files changed

+34
-6
lines changed

BUCK

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,7 @@ rn_library(
727727
"//xplat/js:node_modules__base64_19js",
728728
"//xplat/js:node_modules__event_19target_19shim",
729729
"//xplat/js:node_modules__invariant",
730+
"//xplat/js:node_modules__memoize_19one",
730731
"//xplat/js:node_modules__nullthrows",
731732
"//xplat/js:node_modules__pretty_19format",
732733
"//xplat/js:node_modules__promise",

Libraries/Lists/FlatList.js

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
} from './ViewabilityHelper';
2727
import type {RenderItemType, RenderItemProps} from './VirtualizedList';
2828
import {keyExtractor as defaultKeyExtractor} from './VirtualizeUtils';
29+
import memoizeOne from 'memoize-one';
2930

3031
type RequiredProps<ItemT> = {|
3132
/**
@@ -141,6 +142,10 @@ type OptionalProps<ItemT> = {|
141142
* See `ScrollView` for flow type and further documentation.
142143
*/
143144
fadingEdgeLength?: ?number,
145+
/**
146+
* Enable an optimization to memoize the item renderer to prevent unnecessary rerenders.
147+
*/
148+
strictMode?: boolean,
144149
|};
145150

146151
/**
@@ -578,9 +583,14 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
578583
};
579584
}
580585

581-
_renderer = () => {
582-
const {ListItemComponent, renderItem, columnWrapperStyle} = this.props;
583-
const numColumns = numColumnsOrDefault(this.props.numColumns);
586+
_renderer = (
587+
ListItemComponent: ?(React.ComponentType<any> | React.Element<any>),
588+
renderItem: ?RenderItemType<ItemT>,
589+
columnWrapperStyle: ?ViewStyleProp,
590+
numColumns: ?number,
591+
extraData: ?any,
592+
) => {
593+
const cols = numColumnsOrDefault(numColumns);
584594

585595
let virtualizedListRenderKey = ListItemComponent
586596
? 'ListItemComponent'
@@ -605,7 +615,7 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
605615
* This comment suppresses an error found when Flow v0.111 was deployed.
606616
* To see the error, delete this comment and run Flow. */
607617
[virtualizedListRenderKey]: (info: RenderItemProps<ItemT>) => {
608-
if (numColumns > 1) {
618+
if (cols > 1) {
609619
const {item, index} = info;
610620
invariant(
611621
Array.isArray(item),
@@ -616,7 +626,7 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
616626
{item.map((it, kk) => {
617627
const element = renderer({
618628
item: it,
619-
index: index * numColumns + kk,
629+
index: index * cols + kk,
620630
separators: info.separators,
621631
});
622632
return element != null ? (
@@ -632,14 +642,19 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
632642
};
633643
};
634644

645+
_memoizedRenderer = memoizeOne(this._renderer);
646+
635647
render(): React.Node {
636648
const {
637649
numColumns,
638650
columnWrapperStyle,
639651
removeClippedSubviews: _removeClippedSubviews,
652+
strictMode = false,
640653
...restProps
641654
} = this.props;
642655

656+
const renderer = strictMode ? this._memoizedRenderer : this._renderer;
657+
643658
return (
644659
<VirtualizedList
645660
{...restProps}
@@ -651,7 +666,13 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
651666
removeClippedSubviews={removeClippedSubviewsOrDefault(
652667
_removeClippedSubviews,
653668
)}
654-
{...this._renderer()}
669+
{...renderer(
670+
this.props.ListItemComponent,
671+
this.props.renderItem,
672+
columnWrapperStyle,
673+
numColumns,
674+
this.props.extraData,
675+
)}
655676
/>
656677
);
657678
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"hermes-engine": "~0.11.0",
106106
"invariant": "^2.2.4",
107107
"jsc-android": "^250230.2.1",
108+
"memoize-one": "^5.0.0",
108109
"metro-react-native-babel-transformer": "0.69.1",
109110
"metro-runtime": "0.69.1",
110111
"metro-source-map": "0.69.1",

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4926,6 +4926,11 @@ map-visit@^1.0.0:
49264926
dependencies:
49274927
object-visit "^1.0.0"
49284928

4929+
memoize-one@^5.0.0:
4930+
version "5.2.1"
4931+
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
4932+
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
4933+
49294934
merge-stream@^2.0.0:
49304935
version "2.0.0"
49314936
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"

0 commit comments

Comments
 (0)