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

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

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

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

2 ответа

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

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

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

Я думаю, это зависит от варианта использования

IMO, я выберу opt2 для начала, потому что это просто и легко отлаживать, и opt1, если есть какие-либо проблемы с производительностью (также проверьте, как реализован FlatList: https://reactnative.dev/docs/optimizing-flatlist-configuration). Я чувствую, что opt1 и opt3 могут привести к тому, что list1 отображает данные list2 и наоборот.

Я думаю, что нам редко нужно рендерить большое количество строк с первого раза. Обычно мы используем разбиение на страницы (или непрерывную загрузку при прокрутке вниз), и с этой загрузкой, когда вы переключаете сегмент, данные обновляются, и вам не нужно отображать большие строки.

Плюсы opt2:

  • легко понять код
  • обрабатывать renderRow и selectRow также проще, так как у вас есть 2 отдельных списка.

Я могу перейти к opt1 при возникновении каких-либо проблем, потому что на opt2 весь список повторно монтируется при переключении вкладки, что не очень хорошо (на самом деле, мы можем просто скрыть список, а не отключать его, это потребует больше памяти, но более быстрый рендер )

И производительность по-прежнему плохая, я рассмотрю возможность реализации на нативной стороне:D

Другие вопросы по тегам