React Native: рендеринг бесконечного числа страниц (двунаправленное перелистывание) - PullRequest
0 голосов
/ 23 января 2019

Вопрос

Как люди реализуют бесконечное количество страниц для динамического пролистывания?

Подробности

Если приложение отображает страницу за день, можно ожидать, что она проведет пальцем вправо за предыдущий день и влево за следующий день.

Например, приложение FitNotes делает это, по-видимому, просто: FitNotes app day view

Сдвиг вправо / влево аналогичен нажатию кнопки 5/6.и отображает уже обработанные страницы.В то же время отображаются и новые страницы для соседних дней.

Сначала я подумал, что это то, что вы будете делать, используя карусель, например, используя реагировать-нативно-привязывать-карусель библиотека.Я представлял что-то похожее на приведенный ниже пример, но отображал страницу, используя переменные состояния вместо массива изображений.

Example carousel from the react-native-snap-carousel library

Итак, если бы я хотел визуализироватьстраница с датой вверху, у меня будет массив как часть состояния, например:

carouselElements: [ '2019/01/21', '2019/01/22', '2019/01/23']

Врезанный в карусель ниже, я бы вернул три страницы каждая с датой, отображаемой вthe top.

<Carousel
    ref={(c) => { this._carousel = c; }}
    data={this.props.carouselElements}
    renderItem={this.renderDay}
    sliderWidth={sliderWidth}
    itemWidth={sliderWidth}
    enableSnap 
    firstItem={1}
    initialNumToRender={3}
    maxToRenderPerBatch={3}
    onBeforeSnapToItem={(index) => this.changeEvent(index)}
    useScrollView/>

Задача 1: бесконечно растущий массив

Вы можете начать с Day X и визуализировать смежные два дня раньше времени.Если я проведу пальцем влево, вы получите доступ к Day X+1 и concat Day X+2 к концу массива, а также выполните рендеринг в тот же день.

Массив становится: [ 'Day X-1', 'Day X', 'Day X+1', 'Day X+2']

Дляя могу продолжать сравнивать индекс с 3-дневным окном и отображать только выбранный день и два соседних дня.Но массив будет расти бесконечно, и ваш код будет в лучшем случае O (n).

Проблема 2: Индексирование

a) Предшествующие элементы:

Вы можете начать с Day X и затем провести вправо.Вы сейчас показываете Day X-1.Вы добавляете Day X-2 в начало массива и визуализируете его, чтобы подготовиться ко второму пролистыванию вправо.Проблема в том, что вы добавили элемент с индексом 0. Ваша система указывает на состояние индекса 0, когда он изменился с Day X-1 на Day X-2, поэтому на странице теперь отображается Day X-2.

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

b) Удаление элементов

Если я удаляю элементчтобы сохранить массив маленьким, все меняется, но индекс остается прежним.Индекс теперь указывает на элемент, отличный от предназначенного в массиве, и это отражается на отображаемой странице до того, как индекс может быть исправлен.

Таким образом, мой вопрос: Как люди реализуют динамическийрендеринг страниц до бесконечности с перелистыванием страниц?Кажется, что во многих приложениях он есть, и я не могу найти никого, кто бы говорил об этом.


Правки

РЕДАКТИРОВАТЬ 1: Добавлены изображения с сопровождающими правками, чтобы лучше объяснить мою проблему.

РЕДАКТИРОВАТЬ 2: У меня есть рабочая реализация с реаги-native-swiper , который в основном принимает массивный массив и отображает пакет слайдов, непосредственно примыкающих к отображаемой странице.

<Swiper style={styles.wrapper} 
          showsButtons={false}
          index={currentDateIndex}
          loadMinimal={true}
          loadMinimalSize={1}
          showsPagination={false}
          loop={false}
          onIndexChanged={(index) => dispatch(changeSelectedDayByIndex(index))}
         >
          {dates.map((item) => 
              this.renderDay(item)
            )
          }
</Swiper>

Однако команда dates.map приводит к значительному снижению производительности при запуске.

Редактировать 3: Использование команды slice в массиве дат перед отображением не похоже на вариант, потому что я выполняю рендеринг во время существующего перехода состояния ..

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Это решение основано на упомянутом вами react-native-swiper.Это сложное решение, которое может работать, если кеширование выполнено правильно.Он основан на следующих допущениях:

  • При наличии идентификатора вы можете получить ID + 1 и ID-1..держать массив состояний с 3 идентификаторами: текущий, левый и правый.
    state = {
      pages: ["2", "3", "4"],
      key: 1
    }
    

    Когда вы проводите пальцем влево или вправо, вы можете получить следующий или предыдущий 3 идентификатора и позвонить setState.Метод render будет вызывать локальную кэшированную информацию, чтобы получить атрибуты представления для этих 3 идентификаторов и отобразить новые экраны.Элемент <Swiper> всегда должен указывать на index={1} в качестве исходного параметра и сохранять его таким образом.

    const cache = {
      "0": "zero",
      "1": "one",
      "2": "two",
      "3": "three",
      "4": "four",
      "5": "five",
      "6": "six",
      "7": "seven",
      "8": "eight",
      "9": "nine",
      "10": "ten"
    }
    
    renderItem(item, idx) {
        const itemInt = parseInt(item)
        const style = itemInt % 2 == 0 ? styles.slide1 : styles.slide2
        return (
          <View style={style} key={idx}>
            <Text style={styles.text}>{cache[item]}</Text>
          </View>
        )
      }
    

    Однако, когда вы проводите пальцем, он устанавливает текущий индекс на 2 или 0. Такчтобы он всегда указывал на индекс 1 (опять же, потому что вы переместились и перезагрузились), вы должны принудительно перезагрузить элемент <Swiper>.Вы можете сделать это, установив его ключевой атрибут, который будет определяться переменной состояния, которая всегда изменяется.Это сложная часть.

    onPageChanged(idx) {
        if (idx == 2) {
                                                     //deriving ID+1
          const newPages = this.state.pages.map(i => (parseInt(i)+1).toString())
          this.setState({pages: newPages, key: ((this.state.key+1)%2) })
        } else if (idx == 0) {
                                                     //deriving ID-1
          const newPages = this.state.pages.map(i => (parseInt(i)-1).toString())
          this.setState({pages: newPages, key: ((this.state.key+1)%2) })
        }
      }
    
    render() {
        return (
          <Swiper
            index={1}
            key={this.state.key}
            style={styles.wrapper}
            loop={false}
            showsPagination={false}
            onIndexChanged={(index) => this.onPageChanged(index)}>
            {this.state.pages.map((item, idx) => this.renderItem(item, idx))}
          </Swiper>
        );
      }
    

    Помимо всего этого, вы должны всегда иметь достаточно кэшированной информации для своих идентификаторов.Если доступ к кэшу приближается к концу, обязательно запросите новые данные и удалите некоторое количество кэшированных данных в другом направлении.

    Вот PasteBin для проекта App.js и GitHub , чтобы вы могли проверить всю идею.

    enter image description here

0 голосов
/ 28 января 2019

Это интересно.

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

Проблема 1: бесконечно растущий массив Вам не нужно использовать массив здесь, так как я вижу, что ваши критерии для добавления функции свайпа основаны на дате. Вы должны иметь функции даты, чтобы вычесть / добавить к текущей дате и сделать вызов для того же самого на сервер. После получения данных вам необходимо поддерживать кэш пользователя, который поможет вам сократить количество звонков.

ИЛИ если вы хотите придерживаться только массивов, вы должны загрузить данные Date+-3 только для записи пользователя и сохранить их в кеше (или создание новой БД может быть одним из способов, но это может включать стоимость).

Проблема 2: Индексирование а) Предварительные элементы:

Это не должно быть проблемой, когда вы избавляетесь от массивов. Вы можете работать с состояниями, и один объект должен работать на вас.

б) Снятие элементов

Ваше удаление элементов будет основано на дате, а не на индексе. Поэтому, если вы получили пустой ответ на дату, т.е. Date-1, позвоните по номеру Date-2 и, поскольку у вас есть ограничение в 3 дня, вы можете отключить функцию считывания на нулевом ответе.

( OR Если вы имеете дело только с массивом, вам нужно иметь задание cron, которое обновит данные для вас)

Надеюсь, это поможет, я могу подробнее рассказать, если хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...