2014-05-12 5 views
17

Sto provando a generare un elenco di collegamenti separati da virgola e questa è la mia soluzione.Rendering elenco di collegamenti separati da virgole

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> 
    ); 

    } 
}); 

Mi stavo chiedendo se c'era un modo migliore, più pulito per realizzare questo?

Grazie

risposta

51

Al Khan Academy usiamo un aiutante chiamato intersperse per questo:

/* 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]]); 
} 

che vi permette di scrivere codice come:

var tags = item.tags.map(function(tag, i) { 
    return <Tag key={i} tag={item.tags[i]} />; 
}; 
tags = intersperse(tags, ", "); 
+0

Qualche idea su come si possa passare un elemento (come un '') come secondo parametro? Funziona, ma ricevo un avvertimento riguardo a non specificare una chiave ... Ho provato a racchiudere il '' in una funzione (e generare una chiave casuale) ma questo non sembra molto corretto o funzionare. – thomasjonas

+1

Ho appena realizzato che questo è il modo in cui potrei farlo; passare una funzione come separatore che accetta e idx e quindi utilizzare l'indice del riduttore di array come chiave. – thomasjonas

+1

Qualcosa come in [questo gist] (https://gist.github.com/thomasjonas/f99f48e278fd2dfe82edb2c6f7d6c365) – thomasjonas

6

O semplicemente scrivere le voci di elenco a una lista non ordinata e usa i 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> 
    ); 

    } 
}); 

E il 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; 
} 
+0

Non è davvero esplicito in questo modo –

+0

Mi piace questo approccio. Ho appena usato la classe '.csv' e la faccio funzionare con qualsiasi elemento:'.csv> * ', non solo' ui> li' ed è perfettamente comprensibile – Liero

+0

Mi piace questo approccio perché è semantico, e per quanto posso dire funziona meglio per l'accessibilità. – tenor528

0

Ecco una soluzione che consente <span> s e <br> s e spazzatura come separatore:

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); 
} 

Si filtra gli elementi dell'array Falsey troppo. Ho usato questo per gli indirizzi di formattazione, dove alcuni campi dell'indirizzo non sono compilati.

Utilizza i frammenti per evitare gli avvisi relativi alle chiavi mancanti.

29

Semplicemente

{tags.map((tag, i) => <span key={i}> 
    {!!i && ", "} 
    <Tag tag={tag} /> 
</span>)} 
+1

Dolce e semplice! – Mrchief

+0

@imos Ti dispiacerebbe spiegarlo un po '? '{!! i &&", "}' – Macxim

+1

@Macxim Questa riga stampa la virgola prima di ogni tag tranne prima. Espressione '!! io' converto' i' in booleano. Anche '!! i' può essere sostituito da' i> 0'. – imos

0

La soluzione senza ulteriori tag

reduce è un eccessivo qui e la funzione ottimale da utilizzare è (tecnicamente) flatMap (o chain in Ramda). Sfortunatamente JS non ne fornisce uno (ancora).

<p className="conceps inline list"> 
    {flatMap((concept, i) => 
    [concept, <span key={i} className="separator">&#8226;</span>] 
    , lesson.concepts).slice(-1)} 
</p> 

genera qualcosa come

funzione Tipo • Funzione • funzione di ordine superiore • Applicazione parziale

P.S.

per Ramda è R.addIndex(R.chain) anziché flatMap precedente.