Skip to content

Commit bde1d63

Browse files
kaciebfacebook-github-bot
authored andcommitted
Add getNativeScrollRef to FlatList
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
1 parent 8cb66e3 commit bde1d63

File tree

4 files changed

+137
-2
lines changed

4 files changed

+137
-2
lines changed

Libraries/Lists/FlatList.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ const StyleSheet = require('../StyleSheet/StyleSheet');
1919

2020
const invariant = require('invariant');
2121

22-
import type {ScrollResponderType} from '../Components/ScrollView/ScrollView';
22+
import ScrollView, {
23+
type ScrollResponderType,
24+
} from '../Components/ScrollView/ScrollView';
25+
import type {ScrollViewNativeComponentType} from '../Components/ScrollView/ScrollViewNativeComponentType.js';
2326
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
2427
import type {
2528
ViewToken,
@@ -367,6 +370,24 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
367370
}
368371
}
369372

373+
/**
374+
* Provides a reference to the underlying host component
375+
*/
376+
getNativeScrollRef():
377+
| ?React.ElementRef<typeof View>
378+
| ?React.ElementRef<ScrollViewNativeComponentType> {
379+
if (this._listRef) {
380+
const scrollRef = this._listRef.getScrollRef();
381+
if (scrollRef != null) {
382+
if (scrollRef instanceof ScrollView) {
383+
return scrollRef.getNativeScrollRef();
384+
} else {
385+
return scrollRef;
386+
}
387+
}
388+
}
389+
}
390+
370391
getScrollableNode(): any {
371392
if (this._listRef) {
372393
return this._listRef.getScrollableNode();

Libraries/Lists/VirtualizedList.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,9 @@ class VirtualizedList extends React.PureComponent<Props, State> {
520520
}
521521
}
522522

523-
getScrollRef(): ?React.ElementRef<typeof ScrollView> {
523+
getScrollRef():
524+
| ?React.ElementRef<typeof ScrollView>
525+
| ?React.ElementRef<typeof View> {
524526
if (this._scrollRef && this._scrollRef.getScrollRef) {
525527
return this._scrollRef.getScrollRef();
526528
} else {

Libraries/Lists/__tests__/FlatList-test.js

+59
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,63 @@ describe('FlatList', () => {
9393
);
9494
expect(component).toMatchSnapshot();
9595
});
96+
it('getNativeScrollRef for case where it returns a native view', () => {
97+
jest.resetModules();
98+
jest.unmock('../../Components/ScrollView/ScrollView');
99+
100+
const listRef = React.createRef(null);
101+
102+
ReactTestRenderer.create(
103+
<FlatList
104+
data={[{key: 'outer0'}, {key: 'outer1'}]}
105+
renderItem={outerInfo => (
106+
<FlatList
107+
data={[
108+
{key: outerInfo.item.key + ':inner0'},
109+
{key: outerInfo.item.key + ':inner1'},
110+
]}
111+
renderItem={innerInfo => {
112+
return <item title={innerInfo.item.key} />;
113+
}}
114+
ref={listRef}
115+
/>
116+
)}
117+
/>,
118+
);
119+
120+
const scrollRef = listRef.current.getNativeScrollRef();
121+
122+
// This is checking if the ref acts like a host component. If we had an
123+
// `isHostComponent(ref)` method, that would be preferred.
124+
expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
125+
expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
126+
expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
127+
});
128+
129+
it('getNativeScrollRef for case where it returns a native scroll view', () => {
130+
jest.resetModules();
131+
jest.unmock('../../Components/ScrollView/ScrollView');
132+
133+
function ListItemComponent({item}) {
134+
return <item value={item.key} />;
135+
}
136+
const listRef = React.createRef(null);
137+
138+
ReactTestRenderer.create(
139+
<FlatList
140+
data={[{key: 'i4'}, {key: 'i2'}, {key: 'i3'}]}
141+
ListItemComponent={ListItemComponent}
142+
numColumns={2}
143+
ref={listRef}
144+
/>,
145+
);
146+
147+
const scrollRef = listRef.current.getNativeScrollRef();
148+
149+
// This is checking if the ref acts like a host component. If we had an
150+
// `isHostComponent(ref)` method, that would be preferred.
151+
expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
152+
expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
153+
expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
154+
});
96155
});

Libraries/Lists/__tests__/VirtualizedList-test.js

+53
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,57 @@ describe('VirtualizedList', () => {
281281
}),
282282
);
283283
});
284+
285+
it('getScrollRef for case where it returns a ScrollView', () => {
286+
const listRef = React.createRef(null);
287+
288+
ReactTestRenderer.create(
289+
<VirtualizedList
290+
data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
291+
renderItem={({item}) => <item value={item.key} />}
292+
getItem={(data, index) => data[index]}
293+
getItemCount={data => data.length}
294+
ref={listRef}
295+
/>,
296+
);
297+
298+
const scrollRef = listRef.current.getScrollRef();
299+
300+
// This is checking if the ref acts like a ScrollView. If we had an
301+
// `isScrollView(ref)` method, that would be preferred.
302+
expect(scrollRef.scrollTo).toBeInstanceOf(Function);
303+
});
304+
305+
it('getScrollRef for case where it returns a View', () => {
306+
const listRef = React.createRef(null);
307+
308+
ReactTestRenderer.create(
309+
<VirtualizedList
310+
data={[{key: 'outer0'}, {key: 'outer1'}]}
311+
renderItem={outerInfo => (
312+
<VirtualizedList
313+
data={[
314+
{key: outerInfo.item.key + ':inner0'},
315+
{key: outerInfo.item.key + ':inner1'},
316+
]}
317+
renderItem={innerInfo => {
318+
return <item title={innerInfo.item.key} />;
319+
}}
320+
getItem={(data, index) => data[index]}
321+
getItemCount={data => data.length}
322+
ref={listRef}
323+
/>
324+
)}
325+
getItem={(data, index) => data[index]}
326+
getItemCount={data => data.length}
327+
/>,
328+
);
329+
const scrollRef = listRef.current.getScrollRef();
330+
331+
// This is checking if the ref acts like a host component. If we had an
332+
// `isHostComponent(ref)` method, that would be preferred.
333+
expect(scrollRef.measure).toBeInstanceOf(jest.fn().constructor);
334+
expect(scrollRef.measureLayout).toBeInstanceOf(jest.fn().constructor);
335+
expect(scrollRef.measureInWindow).toBeInstanceOf(jest.fn().constructor);
336+
});
284337
});

0 commit comments

Comments
 (0)