In a React JS / Redux Table, if we add a record to

2019-09-14 06:47发布

问题:

For example, if we have an array

0 => San Francisco
1 => Taipei
2 => San Jose

and use the index as the "key" for every <tr> element like this

this.props.arrData.map((data, i) => {
    return (
        <tr key={i}>
        // ...

it should be fine. When we add to the end of array:

3 => Sacramento

And the index to data mapping is still all good -- just one more mapping is added.

However, I found that even if it is prepended to the array, and still use the index as the "key", it still work perfectly and don't know why.

I thought it should not work because at the very beginning with 1 record:

0 => San Francisco

and it will cache the key 0 as the HTML fragment of San Francisco.

And when a record is prepended:

0 => Taipei
1 => San Francisco

I thought React actually use the 0 as the key to this row, and somehow can "cache" this fragment, and so any <tr> with key=0, it would have it cached as San Francisco, so the table could become:

0 => San Francisco
1 => San Francisco

But it doesn't. So if something was cached, why would it actually work?


P.S. I ended up using:

var countTotalItems = this.props.weatherList.length;

return this.props.weatherList.map((weather, i) => {

  return (
    <tr key={`${countTotalItems - i} ${weather.cityName} ${weather.countryCode}`}>

  // ...

and the key is like: 1 San Francisco US for the last row all the time, even when there are more items added to the array -- essential, just reverse the order by using a key of 1 at the end of array. I used the city and country as well to better identify the row, just in case, for example, if in the future a row can be deleted by the user. But the question is, why if not reversing the order, it still works.

P.P.S. as I put in the comment of one answer: if the row is all text, I found no difference in using key={cityName + i} vs key={i}, but if the row contains an image using <img /> of the weather condition, I do find a difference. If it is key={i} then the newest row will have the previous image for 1 to 2 seconds, and then the correct image will get in. But if it is key={cityName + i}, then the image will be blank, and then 1 to 2 seconds later, the image will get in. The latter behavior is more desirable... the former behavior can be a little confusing to the user.

回答1:

I think you are misunderstanding the point of the key when rendering repeated children. They are used to optimise the rendering when items are added, removed or rearranged and not for "caching" their value.

In your example the rendered html would look something like:

<tr key='0'>Taipei</tr>
<tr key='1'>San Jose</tr>

If a "San Francisco" is added to the front of the array React will have to change every element to the new values and then add a new one at the end for because there isn't an existing element for "San Jose". Now the html would look like:

<tr key='0'>San Francisco</tr>
<tr key='1'>Taipei</tr>
<tr key='2'>San Jose</tr>

Now, if we had used the city name instead of the index and ran through the same example, we would start with:

<tr key='Taipei'>Taipei</tr>
<tr key='San Jose'>San Jose</tr>

Now when the new item is added, React can use the keys to know that "Taipei" and "San Jose" haven't changed and the only changes it needs to make to the DOM is to add an element at the start for the "San Francisco" item. The resulting html would look like:

<tr key='San Francisco'>San Francisco</tr>
<tr key='Taipei'>Taipei</tr>
<tr key='San Jose'>San Jose</tr>

Ultimately, the text on the screen would be the same, but it happened it far fewer updates to the DOM. IF your array had 10000 items in, you can see how much cheaper this approach would be.

Keys must be unique to the item within the list, so if you don't have something unique to use, then the index will have to do, but be aware of the performance implications.

For more details, take a read of the relevant sections of the React docs, here and here.



标签: reactjs redux