Skip to content

Commit

Permalink
expand example with PureComponent usage, explicit extraData prop,…
Browse files Browse the repository at this point in the history
… `initialNumToRender`

Summary: Should help with some common pitfalls, e.g. #12512 (comment).

Reviewed By: yungsters

Differential Revision: D4781833

fbshipit-source-id: 3dec2f0c444645ad710e9ed81390636da4581f0f
  • Loading branch information
sahrens authored and facebook-github-bot committed Mar 28, 2017
1 parent 6f9447e commit acc1edd
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 13 deletions.
100 changes: 92 additions & 8 deletions Libraries/Lists/FlatList.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ type OptionalProps<ItemT> = {
* Rendered at the top of all the items.
*/
ListHeaderComponent?: ?ReactClass<any>,
/**
* Optional custom style for multi-item rows generated when numColumns > 1.
*/
columnWrapperStyle?: StyleObj,
/**
* A marker property for telling the list to re-render (since it implements `PureComponent`). If
* your `renderItem` function depends on anything outside of the `data` prop, stick it here and
* treat it immutably.
*/
extraData?: any,
/**
* `getItemLayout` is an optional optimizations that let us skip measurement of dynamic content if
* you know the height of items a priori. `getItemLayout` is the most efficient, and is easy to
Expand All @@ -75,6 +85,12 @@ type OptionalProps<ItemT> = {
* If true, renders items next to each other horizontally instead of stacked vertically.
*/
horizontal?: ?boolean,
/**
* How many items to render in the initial batch. This should be enough to fill the screen but not
* much more. Note these items will never be unmounted as part of the windowed rendering in order
* to improve perceived performance of scroll-to-top actions.
*/
initialNumToRender: number,
/**
* Used to extract a unique key for a given item at the specified index. Key is used for caching
* and as the react key to track item re-ordering. The default extractor checks `item.key`, then
Expand All @@ -91,26 +107,30 @@ type OptionalProps<ItemT> = {
* content.
*/
onEndReached?: ?(info: {distanceFromEnd: number}) => void,
/**
* How far from the end (in units of visible length of the list) the bottom edge of the
* list must be from the end of the content to trigger the `onEndReached` callback.
* Thus a value of 0.5 will trigger `onEndReached` when the end of the content is
* within half the visible length of the list.
*/
onEndReachedThreshold?: ?number,
/**
* If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make
* sure to also set the `refreshing` prop correctly.
*/
onRefresh?: ?() => void,
/**
* Called when the viewability of rows changes, as defined by the
* `viewablePercentThreshold` prop.
* Called when the viewability of rows changes, as defined by the `viewabilityConfig` prop.
*/
onViewableItemsChanged?: ?(info: {viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void,
onViewableItemsChanged?: ?(info: {
viewableItems: Array<ViewToken>,
changed: Array<ViewToken>,
}) => void,
legacyImplementation?: ?boolean,
/**
* Set this true while waiting for new data from a refresh.
*/
refreshing?: ?boolean,
/**
* Optional custom style for multi-item rows generated when numColumns > 1
*/
columnWrapperStyle?: StyleObj,
/**
* See `ViewabilityHelper` for flow type and further documentation.
*/
Expand Down Expand Up @@ -148,8 +168,71 @@ type DefaultProps = typeof defaultProps;
* renderItem={({item}) => <Text>{item.key}</Text>}
* />
*
* More complex example demonstrating `PureComponent` usage for perf optimization and avoiding bugs.
*
* - By binding the `onPressItem` handler, the props will remain `===` and `PureComponent` will
* prevent wasteful re-renders unless the actual `id`, `selected`, or `title` props change, even
* if the inner `SomeOtherWidget` has no such optimizations.
* - By passing `extraData={this.state}` to `FlatList` we make sure `FlatList` itself will re-render
* when the `state.selected` changes. Without setting this prop, `FlatList` would not know it
* needs to re-render any items because it is also a `PureComponent` and the prop comparison will
* not show any changes.
* - `keyExtractor` tells the list to use the `id`s for the react keys.
*
*
* class MyListItem extends React.PureComponent {
* _onPress = () => {
* this.props.onPressItem(this.props.id);
* };
*
* render() {
* return (
* <SomeOtherWidget
* {...this.props}
* onPress={this._onPress}
* />
* )
* }
* }
*
* class MyList extends React.PureComponent {
* state = {selected: (new Map(): Map<string, boolean>)};
*
* _keyExtractor = (item, index) => item.id;
*
* _onPressItem = (id: string) => {
* // updater functions are preferred for transactional updates
* this.setState((state) => {
* // copy the map rather than modifying state.
* const selected = new Map(state.selected);
* selected.set(id, !state.get(id)); // toggle
* return {selected};
* });
* };
*
* _renderItem = ({item}) => (
* <MyListItem
* id={item.id}
* onPressItem={this._onPressItem}
* selected={!!this.state.selected.get(item.id)}
* title={item.title}
* />
* );
*
* render() {
* return (
* <FlatList
* data={this.props.data}
* extraData={this.state}
* keyExtractor={this._keyExtractor}
* renderItem={this._renderItem}
* />
* );
* }
* }
*
* This is a convenience wrapper around [`<VirtualizedList>`](docs/virtualizedlist.html),
* and thus inherits the following caveats:
* and thus inherits it's props that aren't explicitly listed here along with the following caveats:
*
* - Internal state is not preserved when content scrolls out of the render window. Make sure all
* your data is captured in the item data or external stores like Flux, Redux, or Relay.
Expand Down Expand Up @@ -305,6 +388,7 @@ class FlatList<ItemT> extends React.PureComponent<DefaultProps, Props<ItemT>, vo
arr.push({...v, item, key: keyExtractor(item, index), index});
});
}

_onViewableItemsChanged = (info) => {
const {numColumns, onViewableItemsChanged} = this.props;
if (!onViewableItemsChanged) {
Expand Down
25 changes: 21 additions & 4 deletions Libraries/Lists/SectionList.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,34 @@ type OptionalProps<SectionT: SectionBase<any>> = {
* Rendered at the very end of the list.
*/
ListFooterComponent?: ?ReactClass<any>,
/**
* Rendered at the top of each section. Sticky headers are not yet supported.
*/
renderSectionHeader?: ?(info: {section: SectionT}) => ?React.Element<any>,
/**
* Rendered in between each section.
*/
SectionSeparatorComponent?: ?ReactClass<any>,
/**
* How many items to render in the initial batch. This should be enough to fill the screen but not
* much more. Note these items will never be unmounted as part of the windowed rendering in order
* to improve perceived performance of scroll-to-top actions.
*/
initialNumToRender: number,
/**
* Used to extract a unique key for a given item at the specified index. Key is used for caching
* and as the react key to track item re-ordering. The default extractor checks item.key, then
* falls back to using the index, like react does.
*/
keyExtractor: (item: Item, index: number) => string,
/**
* Called once when the scroll position gets within `onEndReachedThreshold` of the rendered
* content.
*/
onEndReached?: ?(info: {distanceFromEnd: number}) => void,
/**
* How far from the end (in units of visible length of the list) the bottom edge of the
* list must be from the end of the content to trigger the `onEndReached` callback.
* Thus a value of 0.5 will trigger `onEndReached` when the end of the content is
* within half the visible length of the list.
*/
onEndReachedThreshold?: ?number,
/**
* If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make
* sure to also set the `refreshing` prop correctly.
Expand All @@ -88,6 +101,10 @@ type OptionalProps<SectionT: SectionBase<any>> = {
* Set this true while waiting for new data from a refresh.
*/
refreshing?: ?boolean,
/**
* Rendered at the top of each section. Sticky headers are not yet supported.
*/
renderSectionHeader?: ?(info: {section: SectionT}) => ?React.Element<any>,
/**
* Makes section headers stick to the top of the screen until the next one pushes it off. Only
* enabled by default on iOS because that is the platform standard there.
Expand Down
9 changes: 8 additions & 1 deletion Libraries/Lists/VirtualizedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ type OptionalProps = {
* this for debugging purposes.
*/
disableVirtualization: boolean,
/**
* A marker property for telling the list to re-render (since it implements `PureComponent`). If
* your `renderItem` function depends on anything outside of the `data` prop, stick it here and
* treat it immutably.
*/
extraData?: any,
/**
* A generic accessor for extracting an item from any sort of data blob.
*/
Expand All @@ -62,7 +68,8 @@ type OptionalProps = {
horizontal?: ?boolean,
/**
* How many items to render in the initial batch. This should be enough to fill the screen but not
* much more.
* much more. Note these items will never be unmounted as part of the windowed rendering in order
* to improve perceived performance of scroll-to-top actions.
*/
initialNumToRender: number,
keyExtractor: (item: Item, index: number) => string,
Expand Down

0 comments on commit acc1edd

Please sign in to comment.