web-dev-qa-db-fra.com

Le moyen le plus efficace de rendre des éléments JSX lors de l'itération d'un tableau de données dans React

J'ai un tableau qui contient des objets. Je crée une carte de ce tableau pour restituer les noms avec un composant span.

let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];

J'ai utilisé les deux fonctionnalités ci-dessous pour itérer sur ce tableau d'objets, et utiliser map pour rendre des éléments JSX.

Fonctionnalité1:

import React, { Component } from 'react';
class App extends Component {

  render() {
    let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
    const items = data.map((key, i) => {
      return <span key={key.id}>{key.name}</span>;
    });
    return (
      <div>
        {items}
      </div>
    );
  }
}

export default App;

Fonctionnalité2:

import React, { Component } from 'react';
class App extends Component {

  render() {
    let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
    let rows = [];
    data.map((key, i) => {
      rows.Push(<span key={key.id}>{key.name}</span>);
    });
    return (
      <div>
        {rows}
      </div>
    );
  }
}


export default App;

J'ai connu ci-dessus deux manières différentes d'utiliser map et de rendre des éléments JSX. Y a-t-il d'autres façons de faire la même chose, à part ces deux-là? Si oui, lequel est recommandé?

14
Hemadri Dasari

Généralement, je suis cette règle:

Créer un composant qui rend les éléments

// in some file
export const RenderItems = ({data}) => {
  return data && data.map((d, i) => <span key={d.id}>{d.name}</span>) || null
}

Accrochez les RenderItems

import { RenderItems } from 'some-file'

class App extends Component {
  render() {
    // you may also define data here instead of getting data from props
    const { data } = this.props
    return (
      <div>
        <RenderItems data={data} />
      </div>
    )
  }
}

Joindre les données dans le composant

const data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}]
<App data={data} />

Le respect de cette règle n'aura aucune incidence sur les performances, même avec votre deuxième exemple de code, à savoir. pousser des éléments dans un tableau et rendre les éléments. Parce que vous ne travaillez pas directement à l'intérieur du crochet de rendu. Veillez toujours à ce que render ne mette en œuvre aucune logique à l'intérieur.


De plus, je ne créerais pas id juste pour utiliser la clé:

const data = [{"name": "Hi"}, {"name": "Hello"}]
//... and when using index as key
.map((d, i) => <span key={'item-'+i}>
// or,
.map((d, i) => <span key={'item-'+i+'-'+d.name}>

Voir cet article pourquoi je suis cette syntaxe lorsque j'utilise l'index comme clé.


Mettre à jour:

Si vous souhaitez éviter l'utilisation de balises HTML inutiles, vous pouvez utiliser React.Fragment

export const RenderItems = ({data}) => {
  return data && 
    data.map(
      (d, i) => <React.Fragment key={d.id}>{d.name}</React.Fragment>
    ) || null
}
// and when rendering, you just return the component
return <RenderItems data={data} />

Remarque: 

  1. Vous pouvez utiliser <></> comme alias pour <React.Fragment></React.Fragment> uniquement si vous ne possédez aucune propriété supplémentaire. Puisque nous utilisons la propriété de clé dessus, nous ne l'utilisons pas.
  2. Examinez this pour prendre en charge la notation courte de React.Fragment.

Exemple utilisant <></>:

<>{d.name}</>

Cela sera rendu la valeur de d.name en HTML sans balise. Ceci est considéré comme optimal lorsque nous transformons spécifiquement notre conception existante en application réactive. Ou, il pourrait y avoir d'autres cas. Comme, nous allons afficher une liste de définitions:

<dl>
  <dt></dt>
  <dd></dd>
  <dt></dt>
  <dd></dd>
  <dt></dd>
</dl>

Et nous ne voulons pas attacher de balises html inutiles, alors utiliser Fragment nous facilitera la vie:

Exemple:

<>
  <dt>{d.term}</dt>
  <dd>{d.definition}</dd>
</>

Le cas le plus important concerne le rendu de l'élément td dans tr (un composant TR). Si nous ne le faisons pas, nous enfreignons la règle du HTML. Le composant ne sera pas rendu correctement. En réaction, cela vous jettera une erreur.

Update2:

Aussi, si vous avez une longue liste d'accessoires comme ci-dessous:

const {
  items,
  id,
  imdbID,
  title,
  poster,
  getMovieInfo,
  addToFavorites,
  isOpen,
  toggleModal,
  closeModal,
  modalData,
} = props

Vous pouvez envisager une déstructuration comme:

const { items, ...other } = props
// and in your component you can use like:
<div modalData={other.modalData}>

Mais personnellement, je préfère utiliser le premier exemple de code. En effet, lors du développement, je n'ai pas besoin de revenir en arrière sur un autre composant ni de rechercher la console à chaque fois. Dans l'exemple donné, il y a une clé comme modalData={}, donc nous maintenons facilement modalData={other.modalData}. Mais que se passe-t-il s'il est nécessaire de coder comme <div>{modalData}</div>? Ensuite, vous pouvez également accepter ma préférence.

9
Bhojendra Rauniyar

Je ferais ça

const data = [{id: 1, name: 'a'}, {id: 2, name: 'b'}];

export default class App extends PureComponent {
  render() {
    return (
      <div>
        {data.map(({ id, name }) => <span key={id}>{name}</span>)}
      </div>
    );
  }
}

Désormais, votre data n'est pas réinitialisé à chaque rendu, et vous n'avez pas à récupérer des déclarations de variable inutiles.

12
Daniel Lizik

Le premier moyen est meilleur.

  1. Array.prototype.map crée un tableau dans les coulisses et le renvoie après application de la modification sur chaque élément. Functionality-1 crée deux tableaux, tandis que Functionality-2 en crée trois.

  2. Functionality-1 se lit mieux. C'est comme ça que le code de React est écrit. Pour un élément simple comme celui-ci, je sauvegarderais la définition const pour les éléments et placerais l'instruction map dans le JSX à renvoyer directement.

8
Ying Zuo

En règle générale, l'instruction for ou while est le moyen le plus efficace d'itérer un tableau. La façon dont un petit tableau est traité dans un endroit non critique peut être considérée comme une microoptimisation.

L'utilisation de map est idiomatique dans les composants React, car elle est assez rapide et peut renvoyer une valeur dans le cadre d'une expression.

Bien que ce soit un anti-modèle:

let rows = [];
data.map((key, i) => {
  rows.Push(<span key={key.id}>{key.name}</span>);
});

map est supposé mapper les éléments d'un tableau avec d'autres valeurs (d'où le nom), pas pour itérer un tableau au lieu de forEach ou d'une autre boucle. Ce problème peut être suivi avec ESLint array-callback-return rule.

Le composant est sans état et n'a pas besoin d'être une classe Component. Ce peut être un composant fonctionnel ou une classe PureComponent. Puisque data est constant, il n'est pas nécessaire de l'attribuer à chaque rendu:

const data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];

const App = props => <div>
  {data.map(({ id, name }) => <span key={id}>{name}</span>)}
</div>;
4
estus

la première méthode est correcte. utilisez la fonction map pour parcourir le tableau.

export default class App extends React.Component{
    constructor(props){
        super(props);
        this.state = {
          data: [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
        };
 }
    render(){
        return(
            <div>           
                {this.state.data.map((data,index)=>
                      <span key={data.id}>{data.name}</span>
                )}             
        );
    }
}

1
Pravesh Sharma

Vous pouvez utiliser ceci pour une meilleure compréhension

 const data = [{id: 1, name: 'a'}, {id: 2, name: 'b'}];

export default class App extends React.Component {
  render() {
    return (
      <div>
        {data.map((data, dataIndex ) => <span key={dataIndex}>{data.name}</span>)}
      </div>
    );
  }
}

Ici, vous pouvez comprendre que le nom appartient à attribut.

1
Nilanth

J'irais avec la map dans le return(...) car la carte retourne un tableau. C'est plus propre et lisible, ce à quoi je m'efforce personnellement. 

Pour ajouter à la réponse, si le tableau data pouvait changer dans la file, je créerais un nouveau composant de vidage sans état:

const Spanner = props => { return <span key={ props.data.id }>{ props.data.name }</span> };

class App extends Component {
  render() {
    let data = [{"id": "01", "name": "Hi"}, {"id": "02", "name": "Hello"}];
      return (
        <div>
          { 
            data.map( (item, ind) => {
              return (<Spanner key={item.id} data={item.name} />);
            })
          }
        </div>
      );
    }
  }
}

De cette façon, nous pouvons utiliser ce composant clé comme un composant commun partagé entre différents composants. Et au cas où la data change avec le temps (ce qui est généralement le cas), vous pouvez écrire une fonction wrapper dans le composant Spanner et appeler la nouvelle fonction si nécessaire .data=[{"id": "01", "name": "Hi", "userType": "Admin"}, {"id": "02", "name": "Hello", "userType": "Client"}];

const UserWidget = (props) => {
  return (
    <div>
      <h4>{ props.type }</h4>
      <Spanner key={ props.key } data={ props.name }/>
    </div>
  );
}
// now both the UserWidget and the Spanner Components can be used wherever required
// say a dashboard Component wants to use the UserWidget
class Dashboard extends Component {
  render() {
    let data = [{"id": "01", "name": "Hi", "userType": "Admin"}, {"id": "02", "name": "Hello", "userType": "Client"}];
      return (
        <div>
          { 
            data.map( (item, ind) => {
              return (<UserWidget type={ item.userType } key={item.id} data={item.name} />);
            })
          }
        </div>
      );
    }
  }
}

De cette façon, vous ne vous répétez pas et votre composant d'application a toujours le comportement attendu même si le nouveau tableau data possède désormais la nouvelle clé userType. C'est encore ce que je ferais.

1
Tenzin Kunkyab

La fonction toSpan peut être réutilisée.

class App extends React.Component {
  render() {
    const data = [{id: `01`, name: `Hi`}, {id: `02`, name: `Hello`}]
    const toSpan = ({id, name}) => <span key={id}>{name}</span>
    return (
      <div>{data.map(toSpan)}</div>
    )
  }
}
0
sultan