Skip to content

Commit

Permalink
Add getNativeScrollRef to FlatList
Browse files Browse the repository at this point in the history
Summary:
Add a method to get the underlying host component of `FlatList`. Fix flow types in `FlatList` and `VirtualizedList`. Add test cases to test the behavior of the new function in all cases.

Changelog: [General] [Added] - Add getNativeScrollRef method to FlatList component

Reviewed By: TheSavior

Differential Revision: D18302202

fbshipit-source-id: 7005a2bc1dab207434be3f1f4d8fde0b11b3bb4d
  • Loading branch information
kacieb authored and facebook-github-bot committed Dec 3, 2019
1 parent 8cb66e3 commit bde1d63
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 2 deletions.
23 changes: 22 additions & 1 deletion Libraries/Lists/FlatList.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ const StyleSheet = require('../StyleSheet/StyleSheet');

const invariant = require('invariant');

import type {ScrollResponderType} from '../Components/ScrollView/ScrollView';
import ScrollView, {
type ScrollResponderType,
} from '../Components/ScrollView/ScrollView';
import type {ScrollViewNativeComponentType} from '../Components/ScrollView/ScrollViewNativeComponentType.js';
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
import type {
ViewToken,
Expand Down Expand Up @@ -367,6 +370,24 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
}
}

/**
* Provides a reference to the underlying host component
*/
getNativeScrollRef():
| ?React.ElementRef<typeof View>
| ?React.ElementRef<ScrollViewNativeComponentType> {
if (this._listRef) {
const scrollRef = this._listRef.getScrollRef();
if (scrollRef != null) {
if (scrollRef instanceof ScrollView) {
return scrollRef.getNativeScrollRef();
} else {
return scrollRef;
}
}
}
}

getScrollableNode(): any {
if (this._listRef) {
return this._listRef.getScrollableNode();
Expand Down
4 changes: 3 additions & 1 deletion Libraries/Lists/VirtualizedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,9 @@ class VirtualizedList extends React.PureComponent<Props, State> {
}
}

getScrollRef(): ?React.ElementRef<typeof ScrollView> {
getScrollRef():
| ?React.ElementRef<typeof ScrollView>
| ?React.ElementRef<typeof View> {
if (this._scrollRef && this._scrollRef.getScrollRef) {
return this._scrollRef.getScrollRef();
} else {
Expand Down
59 changes: 59 additions & 0 deletions Libraries/Lists/__tests__/FlatList-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,63 @@ describe('FlatList', () => {
);
expect(component).toMatchSnapshot();
});
it('getNativeScrollRef for case where it returns a native view', () => {
jest.resetModules();
jest.unmock('../../Components/ScrollView/ScrollView');

const listRef = React.createRef(null);

ReactTestRenderer.create(
<FlatList
data={[{key: 'outer0'}, {key: 'outer1'}]}
renderItem={outerInfo => (
<FlatList
data={[
{key: outerInfo.item.key + ':inner0'},
{key: outerInfo.item.key + ':inner1'},
]}
renderItem={innerInfo => {
return <item title={innerInfo.item.key} />;
}}
ref={listRef}
/>
)}
/>,
);

const scrollRef = listRef.current.getNativeScrollRef();

// This is checking if the ref acts like a host component. If we had an
// `isHostComponent(ref)` method, that would be preferred.
expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
});

it('getNativeScrollRef for case where it returns a native scroll view', () => {
jest.resetModules();
jest.unmock('../../Components/ScrollView/ScrollView');

function ListItemComponent({item}) {
return <item value={item.key} />;
}
const listRef = React.createRef(null);

ReactTestRenderer.create(
<FlatList
data={[{key: 'i4'}, {key: 'i2'}, {key: 'i3'}]}
ListItemComponent={ListItemComponent}
numColumns={2}
ref={listRef}
/>,
);

const scrollRef = listRef.current.getNativeScrollRef();

// This is checking if the ref acts like a host component. If we had an
// `isHostComponent(ref)` method, that would be preferred.
expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
});
});
53 changes: 53 additions & 0 deletions Libraries/Lists/__tests__/VirtualizedList-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,57 @@ describe('VirtualizedList', () => {
}),
);
});

it('getScrollRef for case where it returns a ScrollView', () => {
const listRef = React.createRef(null);

ReactTestRenderer.create(
<VirtualizedList
data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
renderItem={({item}) => <item value={item.key} />}
getItem={(data, index) => data[index]}
getItemCount={data => data.length}
ref={listRef}
/>,
);

const scrollRef = listRef.current.getScrollRef();

// This is checking if the ref acts like a ScrollView. If we had an
// `isScrollView(ref)` method, that would be preferred.
expect(scrollRef.scrollTo).toBeInstanceOf(Function);
});

it('getScrollRef for case where it returns a View', () => {
const listRef = React.createRef(null);

ReactTestRenderer.create(
<VirtualizedList
data={[{key: 'outer0'}, {key: 'outer1'}]}
renderItem={outerInfo => (
<VirtualizedList
data={[
{key: outerInfo.item.key + ':inner0'},
{key: outerInfo.item.key + ':inner1'},
]}
renderItem={innerInfo => {
return <item title={innerInfo.item.key} />;
}}
getItem={(data, index) => data[index]}
getItemCount={data => data.length}
ref={listRef}
/>
)}
getItem={(data, index) => data[index]}
getItemCount={data => data.length}
/>,
);
const scrollRef = listRef.current.getScrollRef();

// This is checking if the ref acts like a host component. If we had an
// `isHostComponent(ref)` method, that would be preferred.
expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
});
});

0 comments on commit bde1d63

Please sign in to comment.