Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native - good practice: SegmentedControlIOS with ListView

Tags:

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.

1. Two independent dataSource, one ListView (change dataSource of ListView)

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>     );   } } 

2. Two independent dataSource and two independent ListView

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>     );   } } 

3. One dataSource, cloneWithRows on dataSource on change index

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>     );   } } 
like image 848
jonzee Avatar asked Oct 18 '16 14:10

jonzee


1 Answers

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.

like image 152
frank Avatar answered Oct 04 '22 02:10

frank