React Native - good practice: SegmentedControlIOS with ListView
Asked Answered
V

2

24

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>
    );
  }
}
Virgina answered 18/10, 2016 at 14:50 Comment(0)
S
1

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.

Stenography answered 29/10, 2016 at 9:2 Comment(0)
C
1

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:

  • easy to understand the code
  • handle renderRow and selectRow also easier since you have 2 separate list.

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

Climacteric answered 29/5, 2021 at 10:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.