Charlie Harding
Charlie Harding

Reputation: 685

Insert separators between multiple items, with key

I am rendering a few data items in a row, separated by bullets, sometimes omitting these strings if they aren't available/applicable.

const items = [
  age !== null && `age ${age}`,
  nationality && countryName(nationality),
  /* ... */
];
return <Text>{items.filter(x=>x).join(' • ')}</Text>;

I now want to make the age number bold, and so I've replaced the string in the array with a fragment:

[age !== null && (<Fragment>age <Text style={styles.ageNumber}>{age}</Text></Fragment>)]

Reassembling it, I can no longer do join, as that only works on strings. Instead, I've interspersed it with string literals,

const intersperse = (xs, sep) => xs.flatMap((x, i) => (i > 0 ? [sep, x] : [x]));
return <Text>{intersperse(items.filter(x => x), ' • ')}</Text>;

Now that I am passing an array to React, rather than combining it in JavaScript, I get the warning that each child in my array needs a key. How do I handle this nicely, other than by raising more warnings by using the index as the key?

Upvotes: 0

Views: 1435

Answers (2)

tombraider
tombraider

Reputation: 1167

If you have no unique identifier in your array, it's simply a matter of creating a unique index of your choice. Personally, I'd do something like this:

const intersperse = (xs, sep) => xs.flatMap((x, i) => (i > 0 ? [sep, x] : [x]));
return <Text key={`user-info-${Math.random()}`}>{intersperse(items.filter(x => x), ' • ')}</Text>;

Naturally, Math.random() does not necessarily give you a unique number but would usually suffice in the majority of cases. However, if you want to be 100% sure you get a unique key, you could use something like Lodash's uniqueId method instead:

import { uniqueId } from 'lodash/uniqueId';

const intersperse = (xs, sep) => xs.flatMap((x, i) => (i > 0 ? [sep, x] : [x]));
return <Text key={uniqueId('user-info-')}`}>{intersperse(items.filter(x => x), ' • ')}</Text>;

Hope this helps.

EDIT:

Simpler solution as discussed in comments: https://jsfiddle.net/jthcys8v/1/

There's no reason to add things to an array as you're just complicating things. In my opinion this is a much cleaner solution. You could expand on this and call other methods to actually render the Age and Nationality elements, e.g.

<div>
  {userInfo.age && this.renderAge()}
  {userInfo.nationality && this.renderNationality()}
</div>

Upvotes: 0

Ganapati V S
Ganapati V S

Reputation: 1661

You don't need to create array of nodes, instead you can use combination of reduce and Fragment to create final node and just forget about keys.

This technique is especially useful when you don't have data which has unique keys.

Solution here 👇

Edit 5x5m725m84

Upvotes: 2

Related Questions