Skip to content

Commit 967b79f

Browse files
code-smithskv-headless
authored andcommitted
Lazy mouting and rendering of tabs when selected.Changes made to mount tabs only when clicked for first time and render only selected tabs
1 parent f8a78cb commit 967b79f

File tree

3 files changed

+75
-18
lines changed

3 files changed

+75
-18
lines changed

SceneComponent.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const React = require('react');
2+
const ReactNative = require('react-native');
3+
const {Component, } = React;
4+
const {View, StyleSheet, } = ReactNative;
5+
6+
const StaticContainer = require('react-static-container');
7+
8+
const SceneComponent = (Props) => {
9+
const {selected, ...props, } = Props;
10+
return <View {...props}>
11+
<StaticContainer shouldUpdate={selected}>
12+
{props.children}
13+
</StaticContainer>
14+
</View>;
15+
};
16+
17+
module.exports = SceneComponent;

index.js

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const React = require('react');
22
const {
33
PropTypes,
4+
Component,
45
} = React;
56
const ReactNative = require('react-native');
67
const {
@@ -15,9 +16,11 @@ const {
1516
} = ReactNative;
1617
const TimerMixin = require('react-timer-mixin');
1718

19+
const SceneComponent = require('./SceneComponent');
1820
const DefaultTabBar = require('./DefaultTabBar');
1921
const ScrollableTabBar = require('./ScrollableTabBar');
2022

23+
2124
const ScrollableTabView = React.createClass({
2225
mixins: [TimerMixin, ],
2326
statics: {
@@ -56,6 +59,7 @@ const ScrollableTabView = React.createClass({
5659
currentPage: this.props.initialPage,
5760
scrollValue: new Animated.Value(this.props.initialPage),
5861
containerWidth: Dimensions.get('window').width,
62+
sceneKeys: this.updateSceneKeys(this.props.children, [], this.props.initialPage),
5963
};
6064
},
6165

@@ -83,7 +87,12 @@ const ScrollableTabView = React.createClass({
8387
}
8488
}
8589

86-
this.setState({currentPage: pageNumber, });
90+
if(this.props.children.length !== this.state.sceneKeys.length) {
91+
let newKeys = this.updateSceneKeys(this.props.children, this.state.sceneKeys, pageNumber);
92+
this.setState({currentPage: pageNumber, sceneKeys: newKeys, });
93+
}else{
94+
this.setState({currentPage: pageNumber, });
95+
}
8796
},
8897

8998
renderTabBar(props) {
@@ -96,8 +105,26 @@ const ScrollableTabView = React.createClass({
96105
}
97106
},
98107

108+
updateSceneKeys(children, sceneKeys = [], currentPage) {
109+
let newKeys = [];
110+
children.forEach((child, idx) => {
111+
let key = this._makeSceneKey(child, idx);
112+
if(this._keyExists(sceneKeys, key) || currentPage === idx) newKeys.push(key);
113+
});
114+
return newKeys;
115+
},
116+
117+
_keyExists(sceneKeys, key) {
118+
return sceneKeys.find((sceneKey) => key === sceneKey);
119+
},
120+
121+
_makeSceneKey(child, idx) {
122+
return child.props.tabLabel + '_' + idx;
123+
},
124+
99125
renderScrollableContent() {
100126
if (Platform.OS === 'ios') {
127+
const scenes = this._composeScenes();
101128
return (
102129
<ScrollView
103130
horizontal
@@ -133,16 +160,11 @@ const ScrollableTabView = React.createClass({
133160
alwaysBounceVertical={false}
134161
keyboardDismissMode="on-drag"
135162
{...this.props.contentProps}>
136-
{this._children().map((child, idx) => {
137-
return <View
138-
key={child.key}
139-
style={{width: this.state.containerWidth, }}>
140-
{child}
141-
</View>;
142-
})}
163+
{scenes}
143164
</ScrollView>
144165
);
145166
} else {
167+
const scenes = this._composeScenes();
146168
return (
147169
<ViewPagerAndroid
148170
key={this._children().length}
@@ -157,26 +179,43 @@ const ScrollableTabView = React.createClass({
157179
}}
158180
ref={(scrollView) => { this.scrollView = scrollView; }}
159181
{...this.props.contentProps}>
160-
{this._children().map((child, idx) => {
161-
return <View
162-
key={child.key}
163-
style={{width: this.state.containerWidth, }}>
164-
{child}
165-
</View>;
166-
})}
182+
{scenes}
167183
</ViewPagerAndroid>
168184
);
169185
}
170186
},
171187

188+
_composeScenes() {
189+
return this._children().map((child, idx) => {
190+
let key = this._makeSceneKey(child, idx);
191+
return (
192+
<SceneComponent
193+
key={child.key}
194+
selected={(this.state.currentPage === idx)}
195+
style={{width: this.state.containerWidth, }}
196+
>
197+
{this._keyExists(this.state.sceneKeys, key) ? child : <View tabLabel={child.props.tabLabel}/>}
198+
</SceneComponent>
199+
);
200+
});
201+
},
202+
172203
_updateSelectedPage(currentPage) {
173204
let localCurrentPage = currentPage;
174205
if (typeof localCurrentPage === 'object') {
175206
localCurrentPage = currentPage.nativeEvent.position;
176207
}
177-
this.setState({currentPage: localCurrentPage, }, () => {
178-
this.props.onChangeTab({ i: localCurrentPage, ref: this._children()[localCurrentPage], });
179-
});
208+
// scenekeys length and children length is same then no need to update the keys as all are stored by now
209+
if(this.props.children.length !== this.state.sceneKeys.length) {
210+
let newKeys = this.updateSceneKeys(this.props.children, this.state.sceneKeys, localCurrentPage);
211+
this.setState({currentPage: localCurrentPage, sceneKeys: newKeys, }, () => {
212+
this.props.onChangeTab({ i: localCurrentPage, ref: this._children()[localCurrentPage], });
213+
});
214+
}else{
215+
this.setState({currentPage: localCurrentPage, }, () => {
216+
this.props.onChangeTab({ i: localCurrentPage, ref: this._children()[localCurrentPage], });
217+
});
218+
}
180219
},
181220

182221
_updateScrollValue(value) {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
},
2929
"homepage": "https://github.com/brentvatne/react-native-scrollable-tab-view#readme",
3030
"dependencies": {
31+
"react-static-container": "^1.0.1",
3132
"react-timer-mixin": "^0.13.3"
3233
}
3334
}

0 commit comments

Comments
 (0)