Как добавить/удалить элемент в ListView?

Мы можем создать источник данных для ListView следующим образом.

var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});  
var dataSource =  ds.cloneWithRows(['row 1', 'row 2']), };

Но если я хочу добавить элементы или удалить элементы из источника данных, как я могу это сделать? Нужно ли мне всегда вызывать cloneWithRows с обновленным массивом?


person thecodejack    schedule 30.03.2015    source источник


Ответы (2)


Да, позвоните cloneWithRows(...)

Документация React Native не распространяется на объект ListViewDataSource, поэтому может быть полезно прочитать комментарии в исходный код, чтобы увидеть, как это работает.

Некоторые примечания, которые могут быть полезны:

  • Имя cloneWithRows(data) немного вводит в заблуждение, потому что не просто создает клон данных, как следует из названия.

  • Вместо этого он пытается сравнить новые data строки с существующими строками (если они есть) в источнике данных и выясняет, есть ли новые строки для вставки или существующие строки, которые необходимо заменить или удалить.

  • В комментариях к исходному коду отмечается, что данные в источнике данных являются неизменяемыми по замыслу, поэтому правильный способ изменить их — указать обновленный источник данных, т. е. вызвать cloneWithRows(...).

Может показаться нелогичным передавать весь список только для изменения нескольких строк, но есть несколько причин, по которым это имеет смысл:

  • Во-первых, он соответствует общей архитектуре React на основе Flux, где основное внимание уделяется настройке состояний и позволяя компонентам выяснить, как мутировать себя, чтобы отразить новое состояние (подумайте о том, как работает this.props или this.state). Вы можете свободно изменять массив данных, как хотите, за пределами компонента ListView, но как только вы будете готовы обновить компонент, можно будет передать все состояние в компонент, чтобы он мог обновлять себя.

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

  • В-третьих, здесь ничто не исключает возможности поддержки таких методов, как .addRow(..), в будущем. Дело в том, что текущая реализация — неплохое начало, потому что она предоставляет интерфейс на основе состояний, который позволяет разработчикам не беспокоиться о том, как мутирует компонент списка между состояниями.

person tohster    schedule 08.10.2015
comment
Спасибо за объяснение! Меня очень смущает название. Не могли бы вы уточнить, как обновить некоторую информацию подряд? - person Anh Nguyen; 14.04.2017
comment
Как насчет списков с 10 000 строк? Не будет ли производительность блокировать поток пользовательского интерфейса? - person Oliver Dixon; 03.05.2017
comment
Кто прокручивает 10 000 строк за один раз? - person sura2k; 22.08.2017

Если вы посмотрите на расширенный пример Movies из учебника React Native, он реализует поиск, который извлекает новые фильмы из удаленного API. Это означает, что каждый поиск будет обновлять хранилище данных, эффективно добавляя или удаляя элементы. Точное место, где это происходит, здесь:

getDataSource: function(movies: Array<any>): ListView.DataSource {
    return this.state.dataSource.cloneWithRows(movies);
}

https://github.com/facebook/react-native/blob/master/Examples/Movies/SearchScreen.js#L209

Таким образом, похоже, что ваш способ является рекомендуемым методом.

person Colin Ramsay    schedule 30.03.2015
comment
о да... похоже, это единственный способ!!.. Но тогда должен быть какой-то способ... потому что мне может понадобиться управлять состоянием, например положением прокрутки и т. д... - person thecodejack; 30.03.2015
comment
Хороший вопрос, но вы можете сделать это вручную, получив позицию прокрутки ListView ScrollView, а затем установив ее после обновления хранилища данных. Я согласен, что это было бы немного неуклюже, и было бы лучше, если бы вы могли делать это автоматически. Если кто-то из команды RN не может дать лучший ответ, я бы предложил открыть вопрос на трекере Github. - person Colin Ramsay; 30.03.2015
comment
На самом деле, чтобы быть справедливым, кажется, что это ручной процесс даже на полностью нативной iOS: /а> - person Colin Ramsay; 30.03.2015
comment
теперь это имеет больше смысла. В любом случае, я бы предпочел создать оболочку для этого, чтобы RN был намного мощнее с такими функциями. У меня будет предложение по улучшению... Посмотрим, как они отреагируют на это... - person thecodejack; 30.03.2015