diff --git a/BUCK b/BUCK index 175d872524b..ea5bacbb893 100644 --- a/BUCK +++ b/BUCK @@ -727,6 +727,7 @@ rn_library( "//xplat/js:node_modules__base64_19js", "//xplat/js:node_modules__event_19target_19shim", "//xplat/js:node_modules__invariant", + "//xplat/js:node_modules__memoize_19one", "//xplat/js:node_modules__nullthrows", "//xplat/js:node_modules__pretty_19format", "//xplat/js:node_modules__promise", diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index f78ca22968c..8e810372bd7 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -26,6 +26,7 @@ import type { } from './ViewabilityHelper'; import type {RenderItemType, RenderItemProps} from './VirtualizedList'; import {keyExtractor as defaultKeyExtractor} from './VirtualizeUtils'; +import memoizeOne from 'memoize-one'; type RequiredProps = {| /** @@ -141,6 +142,10 @@ type OptionalProps = {| * See `ScrollView` for flow type and further documentation. */ fadingEdgeLength?: ?number, + /** + * Enable an optimization to memoize the item renderer to prevent unnecessary rerenders. + */ + strictMode?: boolean, |}; /** @@ -578,9 +583,14 @@ class FlatList extends React.PureComponent, void> { }; } - _renderer = () => { - const {ListItemComponent, renderItem, columnWrapperStyle} = this.props; - const numColumns = numColumnsOrDefault(this.props.numColumns); + _renderer = ( + ListItemComponent: ?(React.ComponentType | React.Element), + renderItem: ?RenderItemType, + columnWrapperStyle: ?ViewStyleProp, + numColumns: ?number, + extraData: ?any, + ) => { + const cols = numColumnsOrDefault(numColumns); let virtualizedListRenderKey = ListItemComponent ? 'ListItemComponent' @@ -605,7 +615,7 @@ class FlatList extends React.PureComponent, void> { * This comment suppresses an error found when Flow v0.111 was deployed. * To see the error, delete this comment and run Flow. */ [virtualizedListRenderKey]: (info: RenderItemProps) => { - if (numColumns > 1) { + if (cols > 1) { const {item, index} = info; invariant( Array.isArray(item), @@ -616,7 +626,7 @@ class FlatList extends React.PureComponent, void> { {item.map((it, kk) => { const element = renderer({ item: it, - index: index * numColumns + kk, + index: index * cols + kk, separators: info.separators, }); return element != null ? ( @@ -632,14 +642,19 @@ class FlatList extends React.PureComponent, void> { }; }; + _memoizedRenderer = memoizeOne(this._renderer); + render(): React.Node { const { numColumns, columnWrapperStyle, removeClippedSubviews: _removeClippedSubviews, + strictMode = false, ...restProps } = this.props; + const renderer = strictMode ? this._memoizedRenderer : this._renderer; + return ( extends React.PureComponent, void> { removeClippedSubviews={removeClippedSubviewsOrDefault( _removeClippedSubviews, )} - {...this._renderer()} + {...renderer( + this.props.ListItemComponent, + this.props.renderItem, + columnWrapperStyle, + numColumns, + this.props.extraData, + )} /> ); } diff --git a/package.json b/package.json index 8b568a1915a..4dd8e76f4a3 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,7 @@ "hermes-engine": "~0.11.0", "invariant": "^2.2.4", "jsc-android": "^250230.2.1", + "memoize-one": "^5.0.0", "metro-react-native-babel-transformer": "0.69.1", "metro-runtime": "0.69.1", "metro-source-map": "0.69.1", diff --git a/yarn.lock b/yarn.lock index 78327049a61..65959b2029d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4926,6 +4926,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +memoize-one@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"