Reputation: 1609
What are the best practices in implementing SegmentedControllIOS
with ListView
? I tried three solutions, all examples contain SegmentedControllIOS
with two segments and two ListView
. I invite you to discuss performance of this three (maybe someone could propose other, better solution). From my perspective examples are given in order from most efficient.
class Example extends Component {
constructor(props) {
super(props);
this.state = {
ds1: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2,}),
ds2: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2,}),
index: 0,
};
}
render() {
return (
<View>
<SegmentedControlIOS
selectedIndex={this.state.index}
values={['ds1', 'ds2']}
onChange={() => this.setState({index: (this.state.index+1)%2})}
/>
<ListView dataSource={this.state.index ? this.state.ds2 : this.state.ds1} />
</View>
);
}
}
class Example extends Component {
constructor(props) {
super(props);
this.state = {
ds1: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2,}),
ds2: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2,}),
index: 0,
};
}
render() {
return (
<View>
<SegmentedControlIOS
selectedIndex={this.state.index}
values={['ds1', 'ds2']}
onChange={() => this.setState({index: (this.state.index+1)%2})}
/>
{this.state.index === 0 ?
(<ListView dataSource={this.state.ds1} />)
:
(<ListView dataSource={this.state.ds2} />)
}
</View>
);
}
}
class Example extends Component {
constructor(props) {
super(props);
this.state = {
ds: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2,}),
ds1: ['some', 'data'],
ds2: ['some', 'other', 'data'],
index: 0,
};
this.onChange = this.onChange.bind(this);
}
onChange() {
this.setState({
ds: this.state.ds.cloneWithRows(this.state.index ? this.ds1 : this.ds2),
index: (this.state.index+1)%2,
})
}
render() {
return (
<View>
<SegmentedControlIOS
selectedIndex={this.state.index}
values={['ds1', 'ds2']}
onChange={this.onChange}
/>
<ListView dataSource={this.state.ds} />
</View>
);
}
}
Upvotes: 24
Views: 907
Reputation: 1086
I think it depends on the use case
IMO, I will choose opt2 to start with because it's simple and easy to debug and opt1 if there's any performance issue (also check how FlatList is implemented: https://reactnative.dev/docs/optimizing-flatlist-configuration). I feel opt1 and opt3 can leads to the case where list1 render the data of list2 and vice versa
I think, there's rarely we need to render a large of rows on the first time. Usually, we use paging (or continuous loading when scroll to the bottom) and with that loading, when you switch the segment, the data is refreshed and you don't have to render a large of rows.
The pros of opt2 is:
I may go to opt1 when having any issue because on opt2, the whole list is re-mount when switching tab, which is not good (Actually, we can just hide the list instead of unmount it, will cost more memory, but faster render)
And the performance is still bad, I will consider to implement it on native side :D
Upvotes: 1
Reputation: 1342
Third way will be best. When you use cloneWithRows
the ListView
uses the DataSource
's rowHasChanged
function to know what rows it now needs to re-render. Since 'some'
in the first row of ds1
will match 'some'
in the first row of ds2
that row will not be re-rendered.
In case 1 you're not taking advantage of the DataSource
object's state, the ListView
sees that it's trying to render a completely different (possibly non-comparable) data source.
In case 2 you might get some fun rendering artifacts from switching out a heavy weight scrollable component.
Upvotes: 1