2015-05-22 10 views
10

Stavo cercando di animare l'inserimento e la rimozione dell'elenco con ReactCSSTransitionGroup, ma l'animazione di rimozione anima sempre solo l'ultimo elemento dell'elenco invece del uno che viene rimosso.La rimozione di un elemento fa sì che React rimuova l'ultimo nodo DOM invece di quello associato a quell'elemento

Here's a jsbin to illustrate this problem. Prova a premere il pulsante "Aggiungi" per verificare che l'animazione di inserimento funzioni effettivamente come previsto, quindi fai clic sulla "x" accanto a qualsiasi elemento per vedere il problema in cui è animato l'ultimo elemento della lista anziché quello che hai provato a rimuovere.

Ho fatto qualcosa di sbagliato durante l'impostazione di TransitionGroup o mi manca qualcosa nelle definizioni di transizione CSS?

risposta

15

si verifica questo problema, perché si sta utilizzando index come chiave:

Reagire utilizza la proprietà key durante DOM virtuale diffing di capire quale elemento è stato rimosso, ma gli indici non potrà mai servire a tale scopo sufficientemente.

Considerate questo esempio: si inizia con la seguente matrice, che si traduce nella seguente struttura DOM:

const arr = [2, 4, 6, 8]; 

<li key={0}>2</li> 
<li key={1}>4</li> 
<li key={2}>6</li> 
<li key={3}>8</li> 

Poi immaginate si rimuove l'elemento in corrispondenza dell'indice 2. Ora avete il seguente array, e la seguente struttura DOM:

const arr = [2, 4, 8]; 

<li key={0}>2</li> 
<li key={1}>4</li> 
<li key={2}>8</li> 

Si noti che il 8 ora risiede a indice 2; React vede che la differenza tra questa struttura DOM e l'ultima è che manca li con la chiave 3, quindi la rimuove. Pertanto, indipendentemente dall'elemento della matrice rimosso, la struttura DOM risultante mancherà di li con la chiave 3.

La soluzione consiste nell'utilizzare un identificatore univoco per ciascun elemento nell'elenco; in un'applicazione reale, potresti avere un campo id o un'altra chiave primaria da utilizzare; per un app come questo, è possibile generare un ID incrementale:

let id = 0; 
class List extends Component { 
    constructor() { 
    this.state = { 
     items: [{id: ++id, value: 1}, {id: ++id, value: 2}] 
    } 

    // ... 
    } 

    _onClick(e) { 
    this.state.items.push({id: ++id, value: Math.round(Math.random() * 10)}) 
    this.setState({items: this.state.items}) 
    } 

    // ... 

    render() { 
    let items = this.state.items 
    let nodes = items.map((item, index) => { 
     let idx = index 
     return (<Item key={item.id} value={item.value} index={index} _delete={this._onDelete}/>) 
    }) 

    // ... 
    } 
} 

esempio di lavoro: http://jsbin.com/higofuhuni/2/edit

+0

Ah, hai ragione! Non posso credere di averlo perso ... Non posso ringraziarti abbastanza per lo sforzo che hai messo nello spiegare la soluzione così chiaramente per me! Stavo creando un componente che visualizza un elenco di file caricati, quindi anche se non hanno un ID su di essi, posso assegnare loro id temporanei che sono unici (e non cambiano quando cambiano gli elementi della lista) proprio come hai descritto tu. Grazie ancora! – user14412

+1

@Michelle Tilley: Non riesco a vedere l'output in jsbin. Potete per favore aiutarmi a ottenere l'output dal momento che non mi è chiaro sopra il concetto in vizio di codifica –

Problemi correlati