3

In my React app I render an array of items returned from the server, using the database id's as keys.

items.map(item => <Item key={item.id}/>)

This works fine, but now I want to do optimistic updating, so I insert new items into the array before submitting them to the server, and then add the database id when the post operation is done. Now my array briefly contains items with no id's causing errors due to the missing keys.

What to do? I know using the index as key is considered an anti-pattern (https://www.menubar.io/react-keys-index/), so that's out of the question. I also don't want to generate new unique id's for the items because then they will all have two unique id's once they have been saved to the database. I considered using random keys for the unsaved objects, but that seems like a precarious solution.

Is there a best practice solution for this situation? I can't be the first person to encounter this issue.

Simon Christiansen
  • 619
  • 1
  • 6
  • 17

2 Answers2

2

If you are only ever appending to the list you could use an id that is derived from the array index and is guaranteed to never collide with backend ids. Something like the index as a negative value if you have incrementing primary keys in your backend or a string `New-${index}`.

Alternatively as you can't know the backend id in advance I don't see another solution else then using an uuid generator to temporarily generate an id for that item. Such an id is practically collision free.

Using the index is very risky as one of the other items could already use that id.

trixn
  • 15,761
  • 2
  • 38
  • 55
1

Since the id of the items which are being updated in the database will most likely change on successful post request, you might use index as keys for those particular items like

 items.map((item, index) => <Item key={item.id || index}/>)

One likely disadvantage of using the above approach is when one of your item.id coincides with index, so depending on your use case you could choose to use index or a randomId for only those items which aren't yet updated in the database.

P.S. Make sure you are not generating a randomId in the render method since it leads to performance issues causing the component to remount on every rerender

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • 1
    The problem, as you say, is guaranteeing uniqueness. Neither index nor randomId can be guaranteed not to coincide with one of the id's. – Simon Christiansen Apr 16 '18 at 13:19
  • you might make use of uuid to generate a unique id which is a random unique value – Shubham Khatri Apr 16 '18 at 14:52
  • this has a numberof issues - the key will change when the item loads, resetting all state (input forms, animations, `useState`), and this doesn't properly support anything but appending to the list, for the same reason (all the input contents stay where they are, on the (now) wrong list item) – somebody Jun 21 '23 at 03:38