Skip to content

Commit 5de2c88

Browse files
committed
replace ScrollView with FlatList in PickerModal for better performance
1 parent ebd1c67 commit 5de2c88

File tree

2 files changed

+21
-51
lines changed

2 files changed

+21
-51
lines changed

src/components/picker/PickerModal.js

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3-
import {StyleSheet, ScrollView, TextInput} from 'react-native';
3+
import {StyleSheet, FlatList, TextInput} from 'react-native';
44
import _ from 'lodash';
55
import {Constants} from '../../helpers';
66
import {BaseComponent} from '../../commons';
@@ -25,12 +25,13 @@ class PickerModal extends BaseComponent {
2525
}),
2626
searchPlaceholder: PropTypes.string,
2727
onSearchChange: PropTypes.func,
28+
listProps: PropTypes.object,
2829
};
2930

3031
static defaultProps = {
3132
searchPlaceholder: 'Search...',
3233
searchStyle: {},
33-
}
34+
};
3435

3536
state = {
3637
scrollHeight: undefined,
@@ -41,51 +42,14 @@ class PickerModal extends BaseComponent {
4142
this.styles = createStyles(this.props);
4243
}
4344

44-
componentWillReceiveProps(nextProps) {
45-
this.scrollToSelected(nextProps.scrollPosition);
46-
}
47-
48-
onScrollViewLayout = ({
49-
nativeEvent: {
50-
layout: {height},
51-
},
52-
}) => {
53-
this.setState({scrollHeight: height}, () => {
54-
this.scrollToSelected();
55-
});
56-
};
57-
58-
onScrollViewContentSizeChange = (contentWidth, contentHeight) => {
59-
this.setState({scrollContentHeight: contentHeight}, () => {
60-
this.scrollToSelected();
61-
});
62-
};
63-
64-
scrollToSelected(scrollPosition = this.props.scrollPosition) {
65-
const isSearchFocused = _.invoke(this.search, 'isFocused');
66-
if (!scrollPosition || isSearchFocused) return;
67-
68-
const {scrollHeight, scrollContentHeight} = this.state;
69-
if (this.scrollView && scrollHeight && scrollContentHeight) {
70-
const pageNumber = Math.floor(scrollPosition / scrollHeight);
71-
const numberOfPages = Math.ceil(scrollContentHeight / scrollHeight);
72-
73-
if (pageNumber === numberOfPages - 1) {
74-
this.scrollView.scrollToEnd({animated: false});
75-
} else {
76-
this.scrollView.scrollTo({x: 0, y: pageNumber * scrollHeight, animated: false});
77-
}
78-
}
79-
}
80-
8145
renderSearchInput() {
8246
const {showSearch, searchStyle, searchPlaceholder, onSearchChange} = this.props;
8347
if (showSearch) {
8448
return (
8549
<View style={this.styles.searchInputContainer}>
86-
<Image style={this.styles.searchIcon} source={Assets.icons.search}/>
50+
<Image style={this.styles.searchIcon} source={Assets.icons.search} />
8751
<TextInput
88-
ref={r => this.search = r}
52+
ref={r => (this.search = r)}
8953
style={[this.styles.searchInput, {color: searchStyle.color}]}
9054
placeholderTextColor={searchStyle.placeholderTextColor}
9155
selectionColor={searchStyle.selectionColor}
@@ -100,7 +64,7 @@ class PickerModal extends BaseComponent {
10064
}
10165

10266
render() {
103-
const {visible, enableModalBlur, topBarProps, children} = this.props;
67+
const {visible, enableModalBlur, topBarProps, listProps, children} = this.props;
10468
return (
10569
<Modal
10670
animationType={'slide'}
@@ -111,14 +75,15 @@ class PickerModal extends BaseComponent {
11175
>
11276
<Modal.TopBar {...topBarProps} />
11377
{this.renderSearchInput()}
114-
<ScrollView
115-
ref={r => (this.scrollView = r)}
116-
onLayout={this.onScrollViewLayout}
117-
onContentSizeChange={this.onScrollViewContentSizeChange}
118-
keyboardShouldPersistTaps="always"
119-
>
120-
<View style={this.styles.modalBody}>{children}</View>
121-
</ScrollView>
78+
79+
<FlatList
80+
data={_.times(React.Children.count(children))}
81+
renderItem={({index}) => {
82+
return React.Children.toArray(children)[index];
83+
}}
84+
keyExtractor={(item, index) => index}
85+
{...listProps}
86+
/>
12287
</Modal>
12388
);
12489
}

src/components/picker/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ class Picker extends TextInput {
117117
* Icon asset source for showing on the right side, appropriate for dropdown icon and such
118118
*/
119119
rightIconSource: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
120+
/**
121+
* Pass props to the list component that wraps the picker options (allows to control FlatList behavior)
122+
*/
123+
listProps: PropTypes.object,
120124
};
121125

122126
static defaultProps = {
@@ -265,7 +269,7 @@ class Picker extends TextInput {
265269
}
266270

267271
renderExpandableModal() {
268-
const {mode, enableModalBlur, topBarProps, showSearch, searchStyle, searchPlaceholder} = this.getThemeProps();
272+
const {mode, enableModalBlur, topBarProps, showSearch, searchStyle, searchPlaceholder, listProps} = this.getThemeProps();
269273
const {showExpandableModal, selectedItemPosition} = this.state;
270274
return (
271275
<PickerModal
@@ -281,6 +285,7 @@ class Picker extends TextInput {
281285
searchStyle={searchStyle}
282286
searchPlaceholder={searchPlaceholder}
283287
onSearchChange={this.onSearchChange}
288+
listProps={listProps}
284289
>
285290
{this.appendPropsToChildren(this.props.children)}
286291
</PickerModal>

0 commit comments

Comments
 (0)