0

I have a simple <Messages /> React component that shows the error/alert/success messages.

The code is simple as this:

render: function () {
            return <div>{this.state.messages.map(function (message) {
                return (<div className={message.type}>{message.text}</div>);
            })}</div>;
        }

The error Warning: Each child in an array or iterator should have a unique "key" occurs because I don't have a key in the <div />. But my message doesn't have a field that I could call a "key". I thought to use message.text as key, but it's a little weird...

My idea is simple: create a count variable and use that as a key. As this:

render: function () {
    var count = 0;
    return <div>{this.state.messages.map(function (message) {
        var keyValue = count++;
        return (<div key={keyValue} className={message.type}>{message.type}</div>);
    })}</div>;
}

Is there a problem in use this solution for this specific case?

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Dherik
  • 17,757
  • 11
  • 115
  • 164
  • 4
    Well you don't need to do that... the second argument in `map` is the index value. `.map(function (message, index) { return
    })`. The best keys are ones that describe the data as long as its unique.
    – azium Feb 19 '16 at 18:52
  • 2
    AFAIK using index for `key` kind of defeats the purpose of using a key, since the default React behavior reconciles by index to begin with. If the `message.text` is going to be unique (ie you know you don't show the same message twice) I would just use that as the `key`. – Aaron Beall Feb 19 '16 at 20:15

1 Answers1

2

As pointed out by @azium in the comments, you could use index as the key:

return <div>{this.state.messages.map(function (message, index) {
  return (<div key={index} className={message.type}>{message.text}</div>);
})}</div>;

For simple use this is fine. However, this means that each time the list is rendered, the first item has key=0, the second one has key=1 etc.

These keys are unique, but will lead to strange results if the message list changes. React uses the keys to track changes, and wants the same key to always identify the same record. React uses this to do efficient updating when one item in the list changes. If you add a message to the the list, or rearrange the order, react will produce really strange results. So the simple method above does not work when the list changes between renders.

In those cases, it is probably better (as also suggested by @azium in comments), to use a key that uniquely identifies the item (the index does not do this).

Probably something stored in the message itself, such as a unique ID:

return <div>{this.state.messages.map(function (message) {
  return (<div key={message.ID} className={message.type}>{message.text}</div>);
})}</div>;
wintvelt
  • 13,855
  • 3
  • 38
  • 43
  • I don't have a key (id) for message. I thought to generate something like a hash to each message using the message content. But I can't find a simple way to do that. – Dherik Feb 19 '16 at 21:24
  • You could simply try to use `message.text` as the key. Or a hash of it (see e.g. [here](http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery)). Only if the text is unique this will work. Otherwise, the code creating the message should be updated, to provide you with a unique ID (or timestamp) of some kind. – wintvelt Feb 20 '16 at 11:14