161

FlatList does not seem to be working. I get this warning.

VirtualizedList: missing keys for items, make sure to specify a key property on each item or provide a custom keyExtractor.

Code:

<FlatList 
  data={[{name: 'a'}, {name: 'b'}]} 
  renderItem={
    (item) => <Text key={Math.random().toString()}>{item.name}</Text>
  } 
  key={Math.random().toString()} />
Edison D'souza
  • 4,551
  • 5
  • 28
  • 39
  • 3
    @Li357 ... and persistent if the data is unchanged. Random keys will cause rerendering every item on every data change, which would be very inefficient. – Jules Mar 14 '18 at 09:31
  • 1
    as described below it should be a string, there is a disccusion on official repo [here](https://github.com/facebook/react-native/issues/19237). I think react-native team wanted to save users to not use index as a key but it is not a good solution. I should be able to use db id as a key. i don't have to convert it to a string. – peja May 29 '20 at 15:54

13 Answers13

372

Simply do this:

<FlatList 
  data={[{name: 'a'}, {name: 'b'}]} 
  renderItem={
    ({item}) => <Text>{item.name}</Text>
  } 
  keyExtractor={(item, index) => index.toString()}
/>

Source: here

Hendy Irawan
  • 20,498
  • 11
  • 103
  • 114
Ray
  • 9,184
  • 3
  • 27
  • 44
  • {item.name} did not work. But {item.item.name} worked for me. May be because I given (item) instead of ({item}) in renderItem. Thanks @Raymond – Edison D'souza Jun 14 '17 at 15:01
  • Why renderItem={ (item) => {item.name}} works and renderItem={ (item) => {{item.name}} } doesn't work? – Rahul Rastogi Nov 03 '17 at 10:47
  • 1
    Because of the curly braces. If you're going to use curly braces you need to add a return statement. – Ray Nov 03 '17 at 14:43
  • 8
    This may not work. After deleting and adding some elements, it started to display duplicated items. I think the purpose of keyExtractor is to uniquely an item. Ideally you should have an unique id for each item and use the the id as the key. e.g. keyExtractor={item => item.id} – JustWonder Jan 19 '18 at 05:37
  • 2
    @JustWonder - right; if your list is going to have items removed, you can't use the index as a key, and you have to find another way of generating a unique key for each item. For the case where stuff is only ever added, this approach is fine. – Jules Mar 14 '18 at 13:30
  • @Jules is correct. It is preferable to use a unique ID that was generated from the server for example than to use the index number. But for the sake of simplicity, I used the index instead. – Ray Mar 14 '18 at 17:20
  • 21
    the returned index has to be a string: `keyExtractor={(item, index) => index.toString()}` – roadev May 07 '18 at 20:11
  • @roadev comment helps if you get the warning in stacktrace complaining about the key being a type other than String. – P Fuster Sep 02 '18 at 21:55
  • @roadev Good spot, was wondering why I kept getting an error about the index not being a string! – Imdad Sep 24 '18 at 16:34
  • this doesn't work, my error keeps the same, funny is my objects have a string key prop – Matheus Feb 28 '20 at 04:19
48

You don't need to use keyExtractor. The React Native docs are a little unclear but the key property should go in each element of the data array rather than in the rendered child component. So rather than

<FlatList
  data={[{id: 'a'}, {id: 'b'}]}
  renderItem={({item}) => <View key={item.id} />}
/>
// React will give you a warning about there being no key prop

which is what you'd expect, you just need to put a key field in each element of the data array:

<FlatList
  data={[{key: 'a'}, {key: 'b'}]}
  renderItem={({item}) => <View />}
/>
// React is happy!

And definitely don't put a random string as the key.

Ben
  • 706
  • 6
  • 9
17

This worked for me:

<FlatList
  data={[{name: 'a'}, {name: 'b'}]} 
  keyExtractor={(item, index) => index.toString()}
/>
Jan B.
  • 6,030
  • 5
  • 32
  • 53
rjh
  • 171
  • 1
  • 4
13

You can use

 <FlatList   
  data={[]}  
  keyExtractor={(item, index) => index.toString()} 
 />

NOTE : Using index.toString() i.e expected to be string.

Edison D'souza
  • 4,551
  • 5
  • 28
  • 39
Ramusesan
  • 854
  • 2
  • 11
  • 32
6

Have an 'id' in your data

const data = [
{
  name: 'a',
  id: 1
},
{
  name: 'b',
  id: 2
}];

<FlatList 
  data={data}
  renderItem={
    (item) => <Text>{item.name}</Text>
  } 
  keyExtractor={item => item.id}
/>

Hope this helps !!!

3

This did not give any warning (transforming the index to a string):

<FlatList 
  data={[{name: 'a'}, {name: 'b'}]} 
  keyExtractor={(item, index) => index+"" }
  renderItem={
    (item) => <Text>{item.name}</Text>
  } 
/>
JulienRioux
  • 2,853
  • 2
  • 24
  • 37
2

A simple solution is to just give each entry a unique key before rendering with FlatList, since that's what the underlying VirtualizedList needs to track each entry.

 users.forEach((user, i) => {
    user.key = i + 1;
 });

The warning does advice doing this first, or provide a custom key extractor.

Pandemonium
  • 7,724
  • 3
  • 32
  • 51
2

this code work for me :

const content = [
  {
    name: 'Marta',
    content: 'Payday in November: Rp. 987.654.321',
  },]
 
  <FlatList
      data= {content}
      renderItem = { ({ item }) => (
        <View style={{ flexDirection: 'column',             justifyContent: 'center' }}>
      <Text style={{ fontSize: 20, fontWeight: '300', color: '#000000' }}>{item.name}</Text>
      <Text style={{ color: '#000000' }}>{item.content}</Text>
        
        />
      )}
      keyExtractor={(item,index) => item.content}
    />
1

in case your Data is not an object : [in fact it is using each item index (in the array) as a key]

   data: ['name1','name2'] //declared in constructor
     <FlatList
  data= {this.state.data}
  renderItem={({item}) => <Text>{item}</Text>}
  ItemSeparatorComponent={this.renderSeparator}
keyExtractor={(item, index) => index.toString()}
/>
Mahgolsadat Fathi
  • 3,107
  • 4
  • 16
  • 34
1

This worked for me:

<FlatList
  data={items}
    data={[{name: 'a'}, {name: 'b'}]} 
    keyExtractor = () => {
    return new Date().getTime().toString() + (Math.floor(Math.random() * Math.floor(new Date().getTime()))).toString();  };
/>
Raj Shah
  • 668
  • 1
  • 9
  • 23
  • If the Flatlist key extractor is complicated such as generated from Date, Time, etc. The onPress event of a Flatlist Item and Flatlist performance is going to be affected adversely. Always use key extractors that are unique and already present in the data payload. – Surbhit Rao Aug 14 '21 at 13:46
0

Tried Ray's answer but then got an warning that "the key must be an string". The following modified version works well to suppress the original and this string key warning if you don't have a good unique key on the item itself:

keyExtractor={(item, index) => item + index}

Of course if you do have an obvious and good unique key on the item itself you can just use that.

CodeBrew
  • 6,457
  • 2
  • 43
  • 48
0

Make sure to write return statement otherwise it will return nothing..Happened with me.

-3

This worked for me:

<FlatList
  data={items}
  renderItem={({ title }) => <Text>{title}</Text> }}
  keyExtractor={() => Math.random().toString(36).substr(2, 9)} />

Turning the keyExtractor into a string but instead of using index use a random generated number.

When I used keyExtractor={(item, index) => index.toString()}, It never worked and still kicked out a warning. But maybe this works for someone?

0xe1λ7r
  • 1,957
  • 22
  • 31
  • 2
    Keys are supposed to be unique.Using random string is not a good idea. As mentioned above, it will cause unrequired re-rendering since the random function returns a different value if react tries to re-render due to any other change. – Edison D'souza Apr 05 '18 at 07:06
  • I hear you dude thanks for that. But how else would you get a unique string, what if you have like 5 `flatlists` – 0xe1λ7r Apr 05 '18 at 07:15