getItemLayout в FlatList, передающий индекс -1 при первом рендере - PullRequest
3 голосов
/ 05 июля 2019

Я реализую FlatList с initialScrollIndex и getItemLayout.Однако каждый раз, когда мое приложение запускается, оно как-то рендерит первые элементы, а затем переходит к фактическому initialScrollIndex.Это означает, что фактический прирост производительности, который я должен получить, не работает.

При проверке функции getItemLayout я вижу, что при рендеринге первый индекс, который передается, вместо этого -1initialScrollIndex, thus throwing an error and breaking. The other random indexes are passed until initialScrollIndex`.

Есть идеи, почему это может происходить?

FlatList:

renderMonthPerMonth() {
const data = this.deriveMonthPerMonthDataFromProps();
const initialScrollIndex = this.deriveInitialScrollIndex();

return (
  <FlatList
    data={data}
    ref={'flatlist'}
    initialNumToRender={3}
    onLayout={this.onLayout} 
    getItemLayout={this.getItemLayout}
    showsVerticalScrollIndicator={false}
    initialScrollIndex={initialScrollIndex}
    renderItem={this.renderOneMonthPerMonth}
    ListHeaderComponent={this.renderListHeader}
    keyExtractor={el => `${el.monthName}-monthPerMonth`}
    onScrollBeginDrag={() => this.onExpandMenu('scroll')}
    ItemSeparatorComponent={this.renderItemSeparator}
    ListFooterComponent={this.renderFooterComponent}
  />
);
}

getItemLayout:

getItemLayout(data, index) {
const monthAsNumber = moment().month(data[index].monthName).format('M')-1;

const SEPARATOR_HEIGHT = 25;
const MONTH_NAME_CONTAINER_HEIGHT = 55;

const ONE_DAY_HEIGHT = (((width-40)/7)/1.1);
const WEEKS_IN_MONTH = this.weeksInMonth(moment().format('YYYY'), monthAsNumber);

// define oneMonthHeight using weeksInMonth method
const oneMonthHeight = (ONE_DAY_HEIGHT * WEEKS_IN_MONTH) + (MONTH_NAME_CONTAINER_HEIGHT + SEPARATOR_HEIGHT);

return {
  length: oneMonthHeight,
  offset: oneMonthHeight * index,
  index,
}
}

Консоль:

console screenshot

1 Ответ

1 голос
/ 09 июля 2019

У меня есть подозрение, что проблема в опоре renderItem, а затем в методе renderOneMonthPerMonth().

Ссылаясь на документы FlatList :

Это PureComponent, что означает, что он не будет повторно визуализироваться, если реквизит остается мелко-равным. Убедитесь, что все, от чего зависит ваша функция renderItem, передается как реквизит (например, extraData), который не === после обновлений, иначе ваш пользовательский интерфейс может не обновляться при изменениях. Это включает в себя реквизит данных и состояние родительского компонента.

и

renderItem ({элемент: объект, индекс: число, разделители: {выделение: функция, выделение: функция, updateProps: функция (выбор: строка, новыеПроцессы: объект)}}) =>? React.Element

Наличие this.deriveMonthPerMonthDataFromProps() может быть не Чистым (в зависимости от этой опоры, я не могу видеть это).

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

  2. Следующие два, вероятно, суть проблемы: создайте функцию рендеринга, похожую на эту:

      const renderItem = ({ item, index }) => {
        return <DummyComponent item={item} index={index} /> // item and index are not necessarry just demonstrating
      }
  1. Убедитесь, что у вас есть keyExtractor, возвращающий уникальный идентификатор. Иначе это приведет к ошибке, аналогичной вашей проблеме. Попробуйте приведенное ниже как проверку работоспособности
    keyExtractor={(item, index) => index.toString()}

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

Если ваши данные относятся к типу object и вы не полагаетесь на ключи для доступа к определенным частям данных другими методами, вы можете изменить исходные данные на массив объектов, например:

[
  { ...monthOneData },
  { ...monthTwoData },
  { ...monthThreeData }
]

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

Object.keys(this.state.data)

Тогда в вашем FlatList вы можете сделать что-то вроде этого:

<FlatList
  data={Object.keys(this.state.data)}
  renderItem={({item}) => 
    <DummyComponent month={this.state.data[item].month} /> // item is now the key value of the objects (almost like a look up table)
    // also not having curly braces implies an implicit return in this case
  }
/>
...