React Native FlatList, nagging for key when rendering components with a switch

1.2k Views Asked by At

Here's the component code witch fetches items and injects an advertisement every 20 cards, it uses pagination and cards are being added to the existing data when user reaches the bottom of the list:

// every 20 cards, inject an advertisment
var modulusCount = 0;
if ((this.state.labels.length - modCount) % 20 === 0) {
                    this.state.labels.push({type: 'ad'});
                    modulusCount++;
                }

_renderItem = ({item}) => {
    switch (item.type) {
        case 'label':
            return <Card key={item._id} style={styles.card}>
                <CardTitle title={item.description}/>
                <TouchableOpacity style={styles.image} onPress={() => this._showImage(item.imagepath, item.upvotes, item._id)} activeOpacity={0.7}>
                    <CardImage seperator={false} id={item._id} inColumn={false} source={{uri: item.imagepath}}/>
                </TouchableOpacity>
            </Card>;
        case 'ad':
            return (this.state.fbad && this.state.ads ?
                <View key={item._id}>
                    <Card style={styles.card}>
                        <CardTitle title={'Sponsored'}/>
                        <BannerView
                            placementId={placementId}
                            type="large"
                            style={{width: 100}}
                            onPress={() => console.log('click')}
                            onError={this.onBannerAdError}
                        />
                    </Card>
                </View>
                : null );
        default:
            return null;
    }
};

             <View style={styles.view}>
                    <FlatList
                        data={this.state.labels}
                        keyExtractor={this._keyExtractor}
                        renderItem={this._renderItem}
                        onScroll={this._onScroll}
                        refreshing={this.state.refreshing}
                        onRefresh={this.handleRefresh}
                        onEndReached={this.handleLoadMore}
                        onEndReachedThreshold={0.1}
                        onMomentumScrollBegin={() => {
                            this.onEndReachedCalledDuringMomentum = false;
                        }}
                        removeClippedSubviews={true}
                        ListFooterComponent={this.renderFooter}
                    />
                </View>
            </View>

Everything works fine, the ad is displayed every 20 items, but RN complains about the key Warning: Each child in an array or iterator should have a unique "key" prop.

There's definitely something going on with the key of the 'ad' type, what am i doing wrong? How I can make the 'ad' type key unique? I tried several approaches by adding shortid.generate() npm module and inject a key when pushing in the array like this.state.labels.push({key: shortid.generate(), type: 'ad'}) and then setting the key={item.key} in the Card Component but no luck at all.

3

There are 3 best solutions below

1
On

please ensure item._id is unique for every item.

0
On

If you have the modulusCount/modCount, can't you just have something like

`${modulusCount}_key`

as key?

0
On

It seemed that i was using the keyExtractor prop the wrong way, I was using _keyExtractor = (item, index) => item.id, I changed it to _keyExtractor = (item, index) => index;, removed the key={} prop from both cards inside _renderItem Card component and it works like it should.