javascriptlistreact-nativepaginationflatlist

unique "key" prop error using RN FlatList with List ITem


I have a screen in which I display a list of products. I am trying to set up a pagination. I am using List item from react-native-elements and looking at Using RN FlatList as possible in the documentation for this package.

I set up the ability to do pagination, but I got confused in my code. I don't know how to fix it anymore. I would like to know if it would be possible for you to give me a boost and reread my code to give me your opinion.

There for the moment I have the error:

Each child in a list should have a unique "key" prop

I'm a bit lost and need some guidance please. Thanks for any explanation.

The code :

export default class Products extends Component {
  constructor(props) {
    super(props);
      this.state = {
        productId: (props.route.params && props.route.params.productId ? props.route.params.productId : -1),
        listData: '',
        currentPage: 1,
        loadMoreVisible: true,
        loadMoreVisibleAtEnd: false,
        displayArray: []
      }
    };

  initListData = async () => {
    let list = await getProducts(1);
   
    if (list) {
      this.setState({
        displayArray: list,
        loadMoreVisible: (list.length >= 10 ? true : false),
        currentPage: 2
      });
    }
  };

  setNewData = async (page) => {
    let list = await getProducts(parseInt(page));

    if (list) {
      this.setState({
        displayArray: this.state.displayArray.concat(list),
        loadMoreVisible: (list.length >= 10 ? true : false),
        loadMoreVisibleAtEnd: false,
        currentPage: parseInt(page)+1
      });
    }
  };

  loadMore() {
   this.setNewData(this.state.currentPage);
  }

  displayBtnLoadMore() {
    this.setState({
      loadMoreVisibleAtEnd: true
    });
  }

  async UNSAFE_componentWillMount() {
    this.initListData();
  }

  renderItem = ({ item, i }) => (
  <ListItem key={i}
    bottomDivider
    containerStyle={{backgroundColor: i % 2 === 0 ? '#fde3a7' : '#fff' }}
    onPress={() => this.props.navigation.navigate('ProductDetails', {productId:parseInt(item.id)})}>
    <Icon name='shopping-cart' />
    <ListItem.Title style={{width: '65%', fontSize: 14, color: i % 2 === 0 ? '#212121' : '#F78400'  }}>{item.name}</ListItem.Title>
    <ListItem.Subtitle style={{ color: '#F78400'}}>{i18n.t("information.cost")}:{item.cost}</ListItem.Subtitle>
  </ListItem>
);

  render() {
  //console.log('displayArray', this.state.displayArray)
    return (
      <View style={{flex: 1}}>
        {this.state.displayArray !== null && this.state.displayArray.length > 0 ? (
          <View style={{ flex: 1}}>
              <SafeAreaView>
                {
                  this.state.displayArray.map((item, i) => (
                    <FlatList
                      keyExtractor={(item, i) => {
                        return item.id;
                      }}
                      data={this.state.displayArray}
                      onEndReached={() => this.displayBtnLoadMore()}
                      renderItem={this.renderItem}
                    />
                  ))
                }
              </SafeAreaView>
              {this.state.loadMoreVisible === true && this.state.loadMoreVisibleAtEnd === true ? (
                  <Button title=" + " onPress={()=>{this.loadMore()}}></Button>
                ) : null
              }
              <View style={styles.container}>
                <Text>{"\n"}</Text>
                <TouchableOpacity
                  style={styles.touchable2}
                  onPress={() => this.props.navigation.goBack()}
                >
                  <View style={styles.container}>
                    <Button
                      color="#F78400"
                      title= 'Back'
                      onPress={() => this.props.navigation.goBack()}>BACK
                    </Button>
                  </View>
                </TouchableOpacity>
              </View>
              <Text>{"\n\n"}</Text>
          </View>
        ) : (
          <View style={styles.container}>
            <Text>{"\n\n" + (this.state.displayArray === null ? i18n.t("products.searching") : i18n.t("products.nodata")) + "\n\n\n"}</Text>
                <Button
                  color="#F78400"
                  title= 'Back'
                  onPress={() => this.props.navigation.goBack()}>BACK
                </Button>
          </View>
        )}
    </View>
    );
  };
}

Solution

  • The problem is not in your list items but in the FlatList itself - you are rendering an array of FlatList components but they don't have unique keys.

    this.state.displayArray.map((item, i) => (
       <FlatList 
         key={item.id} // or key={i} if item doesn't have ID
         ... rest of your flat list props
       />
    ))