J'essaie de produire une liste de liens séparés par des virgules et voici ma solution.
var Item = React.createComponent({
render: function() {
var tags = [],
tag;
for (var i = 0, l = item.tags.length; i < l; i++) {
if (i === item.tags.length - 1) {
tag = <span><Tag key={i} tag={item.tags[i]} /></span>;
} else {
tag = <span><Tag key={i} tag={item.tags[i]} /><span>, </span></span>;
}
tags.Push(tag);
}
return (
<tr>
<td>
{item.name}
</td>
<td>
{tags}
</td>
</tr>
);
}
});
Je me demandais s'il y avait une meilleure façon, plus propre, d'accomplir cela?
Merci
À la Khan Academy, nous utilisons un assistant appelé intersperse
pour ceci:
/* intersperse: Return an array with the separator interspersed between
* each element of the input array.
*
* > _([1,2,3]).intersperse(0)
* [1,0,2,0,3]
*/
function intersperse(arr, sep) {
if (arr.length === 0) {
return [];
}
return arr.slice(1).reduce(function(xs, x, i) {
return xs.concat([sep, x]);
}, [arr[0]]);
}
ce qui vous permet d'écrire du code comme:
var tags = item.tags.map(function(tag, i) {
return <Tag key={i} tag={item.tags[i]} />;
};
tags = intersperse(tags, ", ");
Simplement
{tags.map((tag, i) => <span key={i}>
{i > 0 && ", "}
<Tag tag={tag} />
</span>)}
Dans React 16, cela peut être encore plus simple:
{tags.map((tag, i) => [
i > 0 && ", ",
<Tag key={i} tag={tag} />
])}
Ou simplement écrivez les éléments de la liste sur une liste non ordonnée et utilisez CSS.
var Item = React.createComponent({
render: function() {
var tags = this.props.item.tags.map(function(i, item) {
return <li><Tag key={i} tag={item} /></li>
});
return (
<tr>
<td>
{this.props.item.name}
</td>
<td>
<ul className="list--tags">
{tags}
</ul>
</td>
</tr>
);
}
});
Et le CSS:
.list--tags {
padding-left: 0;
text-transform: capitalize;
}
.list--tags > li {
display: inline;
}
.list--tags > li:before {
content:',\0000a0'; /* Non-breaking space */
}
.list--tags > li:first-child:before {
content: normal;
}
import React from 'react';
import { compact } from 'lodash';
// Whatever you want to separate your items with commas, space, border...
const Separator = () => { ... };
// Helpful component to wrap items that should be separated
const WithSeparators = ({ children, ...props }) => {
// _.compact will remove falsey values: useful when doing conditional rendering
const array = compact(React.Children.toArray(children));
return array.map((childrenItem, i) => (
<React.Fragment key={`${i}`}>
{i > 0 && <Separator {...props} />}
{childrenItem}
</React.Fragment>
));
};
const MyPage = () => (
<WithSeparators/>
<div>First</div>
{second && (<div>Maybe second</div>)}
{third && (<div>Maybe third</div>)}
<div>Fourth</div>
</WithSeparators>
);
Voici une solution qui autorise <span>
s et <br>
s et les fichiers indésirables en tant que séparateur:
const createFragment = require('react-addons-create-fragment');
function joinElements(arr,sep=<br/>) {
let frag = {};
for(let i=0,add=false;;++i) {
if(add) {
frag[`sep-${i}`] = sep;
}
if(i >= arr.length) {
break;
}
if(add = !!arr[i]) {
frag[`el-${i}`] = arr[i];
}
}
return createFragment(frag);
}
Il filtre également les éléments du tableau falsey. J'ai utilisé cela pour formater des adresses, où certains champs d'adresse ne sont pas renseignés.
Il utilise des fragments pour éviter les avertissements concernant les clés manquantes.
La solution sans balises supplémentaires
reduce
est excessif ici et la fonction optimale à utiliser est (techniquement) flatMap (ou chain
en Ramda). Malheureusement, JS n'en fournit pas (encore).
<p className="conceps inline list">
{flatMap((concept, i) =>
[concept, <span key={i} className="separator">•</span>]
, lesson.concepts).slice(-1)}
</p>
génère quelque chose comme
Fonction • Type de fonction • Fonction d'ordre supérieur • Application partielle
P.S.
pour Ramda c'est R.addIndex(R.chain)
au lieu de flatMap
ci-dessus.
Manière la plus facile de faire
const elementsArr = ["a","b,"c"];
let elementsToRender = [] ;
elementsArr.forEach((element, index) => {
let elementComponent = <TAG className="abc" key={element.id}>{element}</TAG>
elementsToRender.Push(elementComponent);
if(index !== (elementsArr.length - 1)){
elementsToRender.Push(", ");
}
});
render(){
return (
<div>{elementsToRender}</div>
)
}
Un simple:
{items.map((item, index) => (
<span key={item.id}>
{item.id}
{index < items.length - 1 && ', '}
</span>
))}