I had a use case where I am rendering a list of tiles based on data fetched from a remote API. For example, the data looks like this -
[
{referrals: 5, reward: 'Reward1'},
{referrals: 10, reward: 'Reward2'},
{referrals: 25, reward: 'Reward3'},
{referrals: 50, reward: 'Reward4'}
]
This list can be modified on the client-side where a random entry (tile) in the list can be spliced/removed, or a new entry (tile) can be added at the end of the list.
There could be duplicate entries in this list so I cannot create a hash/unique key based on the content of the list entry.
Initially, I tried using array index as a key to render the tiles but in this case what ends up happening is, if I splice the entry at index 3
for example, then the entry at index 4
takes its place at index 3
, and for React, since key 3
is intact, while rendering, it just removes the tile at index 4
while keeping the original tile at index 3
still visible, which is undesired behavior.
So based on the above ideas shared by @josthoff and @Markus-ipse I used a client-side self-incrementing counter as a key (Check https://stackoverflow.com/a/46632553/605027)
When data is initially fetched from the remote API, I add a new key attribute to it
let _tiles = data.tiles.map((v: any) => (
{...v, key: this.getKey()}
))
So it looks like below
[
{referrals: 5, reward: 'Reward1', key: 0},
{referrals: 10, reward: 'Reward2', key: 1},
{referrals: 25, reward: 'Reward3', key: 2},
{referrals: 50, reward: 'Reward4', key: 3}
]
When adding a new entry (tile), I make another call to this.getKey()
. By doing this, every entry (tile) has a unique key and React behaves as intended.
I could've used a random hexadecimal key or UUID generator here but for simplicity I went ahead with self-incrementing counter.