jsoendermann / rn-section-list-get-item-layout

:black_square_button: Easy getItemLayout props for react-native SectionLists.
https://medium.com/@jsoendermann/sectionlist-and-getitemlayout-2293b0b916fb
Other
221 stars 32 forks source link

Tries to access out of bounds section #1

Closed wvteijlingen closed 7 years ago

wvteijlingen commented 7 years ago

An error is thrown on this line: https://github.com/jsoendermann/rn-section-list-get-item-layout/blob/master/index.ts#L18.

It tries to access a section with index 8, while the last section index is 7. This causes a "Cannot read property 'data' of undefined" error.

wvteijlingen commented 7 years ago

Very strange, it seems that getItemLayout sometimes gets called with an index that seems out of bounds. I've set up an example with 2 sections, containing 1 row each. The getItemLayout prop is called multiple times with indexes ranging from 0 to 5. I would think that the max index should be 3...

jsoendermann commented 7 years ago

Hey, thanks for opening an issue. Could you send me the code that causes this so that I can take a look?

wvteijlingen commented 7 years ago

I've opened an issue about this on the react-native repo: https://github.com/facebook/react-native/issues/14972. Although, I'm not sure whether it's a problem with React Native or rn-section-list-get-item-layout.

I tried to create an Expo Snack that shows the problem, but couldn't reproduce it there. I'll see if I can whip up a quick example project locally.

wvteijlingen commented 7 years ago

If you drop this into a fresh React Native project, you'll see what happens:

import React, { Component } from 'react';
import { AppRegistry, StyleSheet, View, Text, SectionList, PixelRatio } from 'react-native';
import sectionListGetItemLayout from 'react-native-section-list-get-item-layout';

export default class GetItemLayoutDemo extends Component {

  constructor(props) {
    super(props);

    // This crashes

    // this.getItemLayout = sectionListGetItemLayout(
    //   () => 40,
    //   () => 1 / PixelRatio.get(),
    //   (rowData, sectionIndex, rowIndex) => 40
    // );

    // This works

    this.getItemLayout = (data, index) => {
      console.log(`getItemLayout called with index: ${index}`);
      return { length: 40, offset: 40 * index, index: index };
    };
  }

  render() {
    const sections = [
      {
        key: 'section1',
        data: ['Row']
      },{
        key: 'section2',
        data: ['Row']
      }
    ];

    return (
      <SectionList
        sections={sections}
        keyExtractor={(item, index) => index}
        ItemSeparatorComponent={() => {
          return <View style={{height: 1, backgroundColor: 'red'}} />
        }}
        renderSectionHeader={() => {
          return <Text style={{height: 40, backgroundColor: 'green'}}>Section header</Text>
        }}
        renderItem={() => {
          return <Text style={{height: 40, backgroundColor: 'yellow'}}>Row</Text>
        }}
        getItemLayout={this.getItemLayout}
      />
    );
  }
}

AppRegistry.registerComponent('GetItemLayoutDemo', () => GetItemLayoutDemo);
sjmueller commented 7 years ago

Getting the same problem:

Cannot read property 'data' of undefined

The sectionIndex is out of bounds of the array (1 too big).

jsoendermann commented 7 years ago

Ok, after digging through the react native sources it seems that we have to account for section footers even when using SectionList without a renderSectionFooter prop. For some reason, it doesn't call getItemLayout for section headers which is why the indices we get with @wvteijlingen's code are 1 2 4 and 5 (0 and 3 are the two section headers).

I'll push something before dinner.

jsoendermann commented 7 years ago

I just pushed version 2.0.0 (sectionListGetItemLayout's parameters have changed). Let me know if you try it.

wvteijlingen commented 7 years ago

Thanks for the quick response, it looks very nice! It seems to work great for me. 👍 You'd really think FlatList and SectionList would include such functionality...