Skip to content

Commit acc1edd

Browse files
sahrensfacebook-github-bot
authored andcommitted
expand example with PureComponent usage, explicit extraData prop, initialNumToRender
Summary: Should help with some common pitfalls, e.g. #12512 (comment). Reviewed By: yungsters Differential Revision: D4781833 fbshipit-source-id: 3dec2f0c444645ad710e9ed81390636da4581f0f
1 parent 6f9447e commit acc1edd

File tree

3 files changed

+121
-13
lines changed

3 files changed

+121
-13
lines changed

Libraries/Lists/FlatList.js

+92-8
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ type OptionalProps<ItemT> = {
5757
* Rendered at the top of all the items.
5858
*/
5959
ListHeaderComponent?: ?ReactClass<any>,
60+
/**
61+
* Optional custom style for multi-item rows generated when numColumns > 1.
62+
*/
63+
columnWrapperStyle?: StyleObj,
64+
/**
65+
* A marker property for telling the list to re-render (since it implements `PureComponent`). If
66+
* your `renderItem` function depends on anything outside of the `data` prop, stick it here and
67+
* treat it immutably.
68+
*/
69+
extraData?: any,
6070
/**
6171
* `getItemLayout` is an optional optimizations that let us skip measurement of dynamic content if
6272
* you know the height of items a priori. `getItemLayout` is the most efficient, and is easy to
@@ -75,6 +85,12 @@ type OptionalProps<ItemT> = {
7585
* If true, renders items next to each other horizontally instead of stacked vertically.
7686
*/
7787
horizontal?: ?boolean,
88+
/**
89+
* How many items to render in the initial batch. This should be enough to fill the screen but not
90+
* much more. Note these items will never be unmounted as part of the windowed rendering in order
91+
* to improve perceived performance of scroll-to-top actions.
92+
*/
93+
initialNumToRender: number,
7894
/**
7995
* Used to extract a unique key for a given item at the specified index. Key is used for caching
8096
* and as the react key to track item re-ordering. The default extractor checks `item.key`, then
@@ -91,26 +107,30 @@ type OptionalProps<ItemT> = {
91107
* content.
92108
*/
93109
onEndReached?: ?(info: {distanceFromEnd: number}) => void,
110+
/**
111+
* How far from the end (in units of visible length of the list) the bottom edge of the
112+
* list must be from the end of the content to trigger the `onEndReached` callback.
113+
* Thus a value of 0.5 will trigger `onEndReached` when the end of the content is
114+
* within half the visible length of the list.
115+
*/
94116
onEndReachedThreshold?: ?number,
95117
/**
96118
* If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make
97119
* sure to also set the `refreshing` prop correctly.
98120
*/
99121
onRefresh?: ?() => void,
100122
/**
101-
* Called when the viewability of rows changes, as defined by the
102-
* `viewablePercentThreshold` prop.
123+
* Called when the viewability of rows changes, as defined by the `viewabilityConfig` prop.
103124
*/
104-
onViewableItemsChanged?: ?(info: {viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void,
125+
onViewableItemsChanged?: ?(info: {
126+
viewableItems: Array<ViewToken>,
127+
changed: Array<ViewToken>,
128+
}) => void,
105129
legacyImplementation?: ?boolean,
106130
/**
107131
* Set this true while waiting for new data from a refresh.
108132
*/
109133
refreshing?: ?boolean,
110-
/**
111-
* Optional custom style for multi-item rows generated when numColumns > 1
112-
*/
113-
columnWrapperStyle?: StyleObj,
114134
/**
115135
* See `ViewabilityHelper` for flow type and further documentation.
116136
*/
@@ -148,8 +168,71 @@ type DefaultProps = typeof defaultProps;
148168
* renderItem={({item}) => <Text>{item.key}</Text>}
149169
* />
150170
*
171+
* More complex example demonstrating `PureComponent` usage for perf optimization and avoiding bugs.
172+
*
173+
* - By binding the `onPressItem` handler, the props will remain `===` and `PureComponent` will
174+
* prevent wasteful re-renders unless the actual `id`, `selected`, or `title` props change, even
175+
* if the inner `SomeOtherWidget` has no such optimizations.
176+
* - By passing `extraData={this.state}` to `FlatList` we make sure `FlatList` itself will re-render
177+
* when the `state.selected` changes. Without setting this prop, `FlatList` would not know it
178+
* needs to re-render any items because it is also a `PureComponent` and the prop comparison will
179+
* not show any changes.
180+
* - `keyExtractor` tells the list to use the `id`s for the react keys.
181+
*
182+
*
183+
* class MyListItem extends React.PureComponent {
184+
* _onPress = () => {
185+
* this.props.onPressItem(this.props.id);
186+
* };
187+
*
188+
* render() {
189+
* return (
190+
* <SomeOtherWidget
191+
* {...this.props}
192+
* onPress={this._onPress}
193+
* />
194+
* )
195+
* }
196+
* }
197+
*
198+
* class MyList extends React.PureComponent {
199+
* state = {selected: (new Map(): Map<string, boolean>)};
200+
*
201+
* _keyExtractor = (item, index) => item.id;
202+
*
203+
* _onPressItem = (id: string) => {
204+
* // updater functions are preferred for transactional updates
205+
* this.setState((state) => {
206+
* // copy the map rather than modifying state.
207+
* const selected = new Map(state.selected);
208+
* selected.set(id, !state.get(id)); // toggle
209+
* return {selected};
210+
* });
211+
* };
212+
*
213+
* _renderItem = ({item}) => (
214+
* <MyListItem
215+
* id={item.id}
216+
* onPressItem={this._onPressItem}
217+
* selected={!!this.state.selected.get(item.id)}
218+
* title={item.title}
219+
* />
220+
* );
221+
*
222+
* render() {
223+
* return (
224+
* <FlatList
225+
* data={this.props.data}
226+
* extraData={this.state}
227+
* keyExtractor={this._keyExtractor}
228+
* renderItem={this._renderItem}
229+
* />
230+
* );
231+
* }
232+
* }
233+
*
151234
* This is a convenience wrapper around [`<VirtualizedList>`](docs/virtualizedlist.html),
152-
* and thus inherits the following caveats:
235+
* and thus inherits it's props that aren't explicitly listed here along with the following caveats:
153236
*
154237
* - Internal state is not preserved when content scrolls out of the render window. Make sure all
155238
* your data is captured in the item data or external stores like Flux, Redux, or Relay.
@@ -305,6 +388,7 @@ class FlatList<ItemT> extends React.PureComponent<DefaultProps, Props<ItemT>, vo
305388
arr.push({...v, item, key: keyExtractor(item, index), index});
306389
});
307390
}
391+
308392
_onViewableItemsChanged = (info) => {
309393
const {numColumns, onViewableItemsChanged} = this.props;
310394
if (!onViewableItemsChanged) {

Libraries/Lists/SectionList.js

+21-4
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,34 @@ type OptionalProps<SectionT: SectionBase<any>> = {
5656
* Rendered at the very end of the list.
5757
*/
5858
ListFooterComponent?: ?ReactClass<any>,
59-
/**
60-
* Rendered at the top of each section. Sticky headers are not yet supported.
61-
*/
62-
renderSectionHeader?: ?(info: {section: SectionT}) => ?React.Element<any>,
6359
/**
6460
* Rendered in between each section.
6561
*/
6662
SectionSeparatorComponent?: ?ReactClass<any>,
63+
/**
64+
* How many items to render in the initial batch. This should be enough to fill the screen but not
65+
* much more. Note these items will never be unmounted as part of the windowed rendering in order
66+
* to improve perceived performance of scroll-to-top actions.
67+
*/
68+
initialNumToRender: number,
6769
/**
6870
* Used to extract a unique key for a given item at the specified index. Key is used for caching
6971
* and as the react key to track item re-ordering. The default extractor checks item.key, then
7072
* falls back to using the index, like react does.
7173
*/
7274
keyExtractor: (item: Item, index: number) => string,
75+
/**
76+
* Called once when the scroll position gets within `onEndReachedThreshold` of the rendered
77+
* content.
78+
*/
7379
onEndReached?: ?(info: {distanceFromEnd: number}) => void,
80+
/**
81+
* How far from the end (in units of visible length of the list) the bottom edge of the
82+
* list must be from the end of the content to trigger the `onEndReached` callback.
83+
* Thus a value of 0.5 will trigger `onEndReached` when the end of the content is
84+
* within half the visible length of the list.
85+
*/
86+
onEndReachedThreshold?: ?number,
7487
/**
7588
* If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make
7689
* sure to also set the `refreshing` prop correctly.
@@ -88,6 +101,10 @@ type OptionalProps<SectionT: SectionBase<any>> = {
88101
* Set this true while waiting for new data from a refresh.
89102
*/
90103
refreshing?: ?boolean,
104+
/**
105+
* Rendered at the top of each section. Sticky headers are not yet supported.
106+
*/
107+
renderSectionHeader?: ?(info: {section: SectionT}) => ?React.Element<any>,
91108
/**
92109
* Makes section headers stick to the top of the screen until the next one pushes it off. Only
93110
* enabled by default on iOS because that is the platform standard there.

Libraries/Lists/VirtualizedList.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ type OptionalProps = {
4949
* this for debugging purposes.
5050
*/
5151
disableVirtualization: boolean,
52+
/**
53+
* A marker property for telling the list to re-render (since it implements `PureComponent`). If
54+
* your `renderItem` function depends on anything outside of the `data` prop, stick it here and
55+
* treat it immutably.
56+
*/
57+
extraData?: any,
5258
/**
5359
* A generic accessor for extracting an item from any sort of data blob.
5460
*/
@@ -62,7 +68,8 @@ type OptionalProps = {
6268
horizontal?: ?boolean,
6369
/**
6470
* How many items to render in the initial batch. This should be enough to fill the screen but not
65-
* much more.
71+
* much more. Note these items will never be unmounted as part of the windowed rendering in order
72+
* to improve perceived performance of scroll-to-top actions.
6673
*/
6774
initialNumToRender: number,
6875
keyExtractor: (item: Item, index: number) => string,

0 commit comments

Comments
 (0)