Appearance
Iteration HTML
Tout comme les conditions, il arrive que l’on souhaite répéter plusieurs fois un même pattern au sein d’une structure HTML, en modifiant seulement une partie des informations affichées à chaque itération. C’est le cas, par exemple, pour présenter les éléments présents dans un tableau sous la forme d’une liste à puces.
Itération en JavaScript natif
En JavaScript simple, pour obtenir une liste à puces à partir d'un tableau, il est nécessaire d'itérer sur le tableau pour créer manuellement chaque élément de la liste :
html
<ul id="my-list"></ul>js
const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];
const ul = document.getElementById('my-list');
items.forEach(item => {
const li = document.createElement('li'); // Create <li> element.
li.textContent = item; // Add text
ul.appendChild(li); // Add <li> as <ul> child.
});Comme pour les logiques conditionnelles, cette stratégie rend la partie HTML peu explicite.
Itération en framework JS
Les frameworks JS permettent d’introduire la logique itérative directement au niveau de la définition du code HTML :
jsx
export default function App() {
const items = ["Item 1", "Item 2", "Item 3", "Item 4"];
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
};Une expression JavaScript est à nouveau employée pour injecter du code HTML à l'intérieur du composant. La méthode map est utilisée sur le tableau items pour générer une liste de valeurs à partir de celles du tableau : la liste générée correspond à une balise du type <li> pour chaque case du tableau items.
NOTE
📌 Les expressions JavaScript injectées dans le code HTML peuvent retourner un bloc de code HTML ou bien un tableau de plusieurs blocs. Dans le second cas, les différents blocs seront simplement concaténés et ajoutés ensemble au HTML du composant.
Le tableau JavaScript ainsi parcouru peut aussi bien contenir des chaînes de caractères que d’autres types de valeurs ou des objets plus complexes :
jsx
export default function App() {
const items = [
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" },
{ id: 3, name: "Item 3" },
{ id: 4, name: "Item 4" },
];
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
};L’attribut key
Les exemples précédents ajoutent un attribut key à la balise créée de façon itérative. Cet attribut, obligatoire, trouve son intérêt si la liste d’items parcourue venait à changer. Nous verrons en effet dans les prochains chapitres que le framework est en mesure d’adapter la liste affichée en fonction de l’évolution de l’état du tableau : si l’ordre des éléments dans la liste vient à changer, il les réordonnera visuellement aussi.
Dans ce cas, l’attribut key permet d’associer un identifiant unique à chaque bloc HTML générée. Si les blocs doivent être réordonnées, le framework s’appuiera sur l'attribut key pour reconnaître les éléments par rapport à l'état précédent, optimiser le rendu de la nouvelle configuration et conserver l’état interne s'il s'agit de composants.
Il est donc capital que la valeur renseignée au niveau de l’attribut key identifie de façon unique l’objet du tableau qui lui est associé, et non sa position dans le tableau.
WARNING
⚠️ N’utilisez jamais l’index de l’itération comme key. L’index n’est pas lié à l’objet dans le tableau, mais à sa position. Si l’ordre des objets dans le tableau change, leurs indexs respectifs changeront également, ce qui empêchera le framework d'identifier le mouvement des éléments entre le nouvel état et l'état précédent :
jsx
export default function App() {
const items = [...];
return (
<ul>
{items.map((item, index) => (
<!-- Never do that ! -->
<li key={index}>{item.name}</li>
))}
</ul>
);
};🐶 DogCenter
Les expressions itératives simplifient la façon dont nous pouvons générer la gallerie de DogCard dans notre application : plutôt que de définir manuellement les DogCard associées à chacun de nos chiens, nous pouvons itérer directement à partir d'un tableau contenant les informations de l'ensemble des chiens du chenil.
Commençons par créer un tableau regroupant les informations des chiens dans un fichier src/dogsData.js:
js
export default [
{
id: 1,
name: "Buddy",
age: 3,
breed: "Golden Retriever",
pictureUrl: "https://dog-center.com/api/dogs/1.png",
},
{
id: 2,
name: "Luna",
age: 2,
breed: "Labrador Retriever",
pictureUrl: "https://dog-center.com/api/dogs/2.png",
},
...
];INFO
📌 Nous verrons dans les prochains chapitres comment récupérer ces données de façon asynchrone depuis un serveur distant, plutôt que de les définir directement dans notre application front-end.
Importons ensuite ces données au niveau de notre gallerie et itérons pour créer un composant DogCard pour chaque objet du tableau :
jsx
import './App.css'
import dogsData from "./dogsData.js";
import DogCard from "./components/DogCard";
export default function App() {
return (
<div>
<h1>Dog Center</h1>
<div id="dog-gallery">
{dogsData.map((dog) => (
<DogCard
key={dog.id}
name={dog.name}
age={dog.age}
breed={dog.breed}
pictureUrl={dog.pictureUrl}
/>
))}
</div>
</div>
);
}La définition du composant devient immédiatement plus concise et plus flexible : la galerie s'adaptera automatiquement au nombre de chiens présents dans le tableau pour tous les afficher.
Conclusion
La gestion des logiques conditionnelles et itératives influençant la structure HTML de l'application est rendue plus simple et plus explicite grâce à l'usage des frameworks JavaScript. Nous verrons par la suite que ces implémentations permettent également de gérer plus facilement les réactions de l'application à certains changements d'état, provoqués par exemple par l'interaction de l'utilisateur avec l'application.
Vous disposez maintenant des bases pour la création d'une application statique à l'aide d'un framework JavaScript. La prochaine partie du cours se concentrera sur les façons de rendre une application plus interactive.

