VirtualizedSectionList

Reviewed By: yungsters

Differential Revision: D8021463

fbshipit-source-id: 8b65585776cf41e194418d127bca85dbe47ea659
This commit is contained in:
Spencer Ahrens 2018-05-25 14:59:28 -07:00 committed by Facebook Github Bot
parent 488a4c7e1c
commit 26a1eba1ce
1 changed files with 51 additions and 55 deletions

View File

@ -37,12 +37,12 @@ type SectionBase = {
updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, updateProps: (select: 'leading' | 'trailing', newProps: Object) => void,
}, },
}) => ?React.Element<any>, }) => ?React.Element<any>,
ItemSeparatorComponent?: ?React.ComponentType<*>, ItemSeparatorComponent?: ?React.ComponentType<any>,
keyExtractor?: (item: SectionItem, index: ?number) => string, keyExtractor?: (item: SectionItem, index: ?number) => string,
// TODO: support more optional/override props // TODO: support more optional/override props
// FooterComponent?: ?ReactClass<*>, // FooterComponent?: ?ReactClass<any>,
// HeaderComponent?: ?ReactClass<*>, // HeaderComponent?: ?ReactClass<any>,
// onViewableItemsChanged?: ({viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void, // onViewableItemsChanged?: ({viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void,
}; };
@ -54,11 +54,11 @@ type OptionalProps<SectionT: SectionBase> = {
/** /**
* Rendered after the last item in the last section. * Rendered after the last item in the last section.
*/ */
ListFooterComponent?: ?(React.ComponentType<*> | React.Element<any>), ListFooterComponent?: ?(React.ComponentType<any> | React.Element<any>),
/** /**
* Rendered at the very beginning of the list. * Rendered at the very beginning of the list.
*/ */
ListHeaderComponent?: ?(React.ComponentType<*> | React.Element<any>), ListHeaderComponent?: ?(React.ComponentType<any> | React.Element<any>),
/** /**
* Default renderer for every item in every section. * Default renderer for every item in every section.
*/ */
@ -84,11 +84,11 @@ type OptionalProps<SectionT: SectionBase> = {
* Rendered at the bottom of every Section, except the very last one, in place of the normal * Rendered at the bottom of every Section, except the very last one, in place of the normal
* ItemSeparatorComponent. * ItemSeparatorComponent.
*/ */
SectionSeparatorComponent?: ?React.ComponentType<*>, SectionSeparatorComponent?: ?React.ComponentType<any>,
/** /**
* Rendered at the bottom of every Item except the very last one in the last section. * Rendered at the bottom of every Item except the very last one in the last section.
*/ */
ItemSeparatorComponent?: ?React.ComponentType<*>, ItemSeparatorComponent?: ?React.ComponentType<any>,
/** /**
* Warning: Virtualization can drastically improve memory consumption for long lists, but trashes * Warning: Virtualization can drastically improve memory consumption for long lists, but trashes
* the state of items when they scroll out of the render window, so make sure all relavent data is * the state of items when they scroll out of the render window, so make sure all relavent data is
@ -101,7 +101,7 @@ type OptionalProps<SectionT: SectionBase> = {
* If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make * If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make
* sure to also set the `refreshing` prop correctly. * sure to also set the `refreshing` prop correctly.
*/ */
onRefresh?: ?Function, onRefresh?: ?() => void,
/** /**
* Called when the viewability of rows changes, as defined by the * Called when the viewability of rows changes, as defined by the
* `viewabilityConfig` prop. * `viewabilityConfig` prop.
@ -134,10 +134,6 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
Props<SectionT>, Props<SectionT>,
State, State,
> { > {
props: Props<SectionT>;
state: State;
static defaultProps: DefaultProps = { static defaultProps: DefaultProps = {
...VirtualizedList.defaultProps, ...VirtualizedList.defaultProps,
data: [], data: [],
@ -164,6 +160,48 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
return this._listRef; return this._listRef;
} }
constructor(props: Props<SectionT>, context: Object) {
super(props, context);
this.state = this._computeState(props);
}
UNSAFE_componentWillReceiveProps(nextProps: Props<SectionT>) {
this.setState(this._computeState(nextProps));
}
_computeState(props: Props<SectionT>): State {
const offset = props.ListHeaderComponent ? 1 : 0;
const stickyHeaderIndices = [];
const itemCount = props.sections.reduce((v, section) => {
stickyHeaderIndices.push(v + offset);
return v + section.data.length + 2; // Add two for the section header and footer.
}, 0);
return {
childProps: {
...props,
renderItem: this._renderItem,
ItemSeparatorComponent: undefined, // Rendered with renderItem
data: props.sections,
getItemCount: () => itemCount,
getItem,
keyExtractor: this._keyExtractor,
onViewableItemsChanged: props.onViewableItemsChanged
? this._onViewableItemsChanged
: undefined,
stickyHeaderIndices: props.stickySectionHeadersEnabled
? stickyHeaderIndices
: undefined,
},
};
}
render() {
return (
<VirtualizedList {...this.state.childProps} ref={this._captureRef} />
);
}
_keyExtractor = (item: Item, index: number) => { _keyExtractor = (item: Item, index: number) => {
const info = this._subExtractor(index); const info = this._subExtractor(index);
return (info && info.key) || String(index); return (info && info.key) || String(index);
@ -307,7 +345,7 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
_getSeparatorComponent( _getSeparatorComponent(
index: number, index: number,
info?: ?Object, info?: ?Object,
): ?React.ComponentType<*> { ): ?React.ComponentType<any> {
info = info || this._subExtractor(index); info = info || this._subExtractor(index);
if (!info) { if (!info) {
return null; return null;
@ -326,48 +364,6 @@ class VirtualizedSectionList<SectionT: SectionBase> extends React.PureComponent<
return null; return null;
} }
_computeState(props: Props<SectionT>): State {
const offset = props.ListHeaderComponent ? 1 : 0;
const stickyHeaderIndices = [];
const itemCount = props.sections.reduce((v, section) => {
stickyHeaderIndices.push(v + offset);
return v + section.data.length + 2; // Add two for the section header and footer.
}, 0);
return {
childProps: {
...props,
renderItem: this._renderItem,
ItemSeparatorComponent: undefined, // Rendered with renderItem
data: props.sections,
getItemCount: () => itemCount,
getItem,
keyExtractor: this._keyExtractor,
onViewableItemsChanged: props.onViewableItemsChanged
? this._onViewableItemsChanged
: undefined,
stickyHeaderIndices: props.stickySectionHeadersEnabled
? stickyHeaderIndices
: undefined,
},
};
}
constructor(props: Props<SectionT>, context: Object) {
super(props, context);
this.state = this._computeState(props);
}
UNSAFE_componentWillReceiveProps(nextProps: Props<SectionT>) {
this.setState(this._computeState(nextProps));
}
render() {
return (
<VirtualizedList {...this.state.childProps} ref={this._captureRef} />
);
}
_cellRefs = {}; _cellRefs = {};
_listRef: VirtualizedList; _listRef: VirtualizedList;
_captureRef = ref => { _captureRef = ref => {