React Native - хорошая практика: SegmentedControlIOS с ListView

Каковы наилучшие методы реализации SegmentedControllIOS с ListView? Я попробовал три решения, все примеры содержат SegmentedControllIOS с двумя сегментами и двумя ListView. Я приглашаю вас обсудить работу этих трех (возможно, кто-то может предложить другое, лучшее решение). С моей точки зрения, примеры приведены в порядке наиболее эффективных.

1. Два независимых источника данных, один ListView (изменить dataSource 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. Два независимых источника данных и два независимых 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. Один dataSource, cloneWithRows на dataSource по индексу изменения

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

Ответ 1

Третий путь будет лучшим. Когда вы используете cloneWithRows, ListView использует функцию DataSource rowHasChanged, чтобы узнать, какие строки теперь нужно перерисовать. Поскольку 'some' в первой строке ds1 будет соответствовать 'some' в первой строке ds2, эта строка не будет повторно отображаться.

В случае 1 вы не пользуетесь состоянием объекта DataSource, ListView видит, что он пытается отобразить совершенно другой (возможно, несопоставимый) источник данных.

В случае 2 вы можете получить некоторые полезные артефакты рендеринга от переключения прокручиваемого компонента.