En PHP, vous séparez généralement :
// Contrôleur
$users = $userRepository->findAll();
include 'views/users.php';
// Vue (users.php)
<ul>
<?php foreach ($users as $user): ?>
<li><?= htmlspecialchars($user->name) ?></li>
<?php endforeach; ?>
</ul>
En React, logique et rendu sont ensemble dans un composant :
function UserList({ users }) { // Logique ici si nécessaire const activeUsers = users.filter(u => u.active); // Rendu return ( <ul> {activeUsers.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> ); }
Pourquoi ? Parce que la logique d'affichage et le rendu sont intrinsèquement liés. Les séparer artificiellement complique la maintenance.
Manipuler le DOM est lent. Chaque modification peut déclencher un recalcul du layout et un repaint du navigateur.
// Approche classique - chaque ligne touche le DOM document.getElementById('name').textContent = user.name; document.getElementById('email').textContent = user.email; document.getElementById('role').textContent = user.role;
React maintient une copie légère du DOM en mémoire (Virtual DOM). Quand les données changent :
// Vous décrivez juste le résultat souhaité function UserCard({ user }) { return ( <div> <span id="name">{user.name}</span> <span id="email">{user.email}</span> <span id="role">{user.role}</span> </div> ); } // React s'occupe d'optimiser les mises à jour
Dans certains frameworks, les données circulent dans les deux sens : la vue peut modifier le modèle et vice versa. Cela peut créer des boucles et rendre le debugging difficile.
En React, les données descendent toujours du parent vers l'enfant via les props :
App
│
▼ props (users)
UserList
│
▼ props (user)
UserCard
Si un enfant veut modifier des données, il appelle une fonction passée par le parent :
function App() { const [users, setUsers] = useState([]); const deleteUser = (id) => { setUsers(users.filter(u => u.id !== id)); }; return <UserList users={users} onDelete={deleteUser} />; } function UserList({ users, onDelete }) { return ( <ul> {users.map(user => ( <UserCard key={user.id} user={user} onDelete={onDelete} /> ))} </ul> ); } function UserCard({ user, onDelete }) { return ( <div> {user.name} <button onClick={() => onDelete(user.id)}>Supprimer</button> </div> ); }
Les données descendent (props), les actions remontent (callbacks).
Vous décrivez comment faire les choses, étape par étape :
// "Quand le bouton est cliqué, trouve l'élément, modifie son contenu..." $('#btn').click(function() { const count = parseInt($('#count').text()) + 1; $('#count').text(count); if (count > 10) { $('#count').addClass('warning'); } });
Vous décrivez ce que vous voulez en fonction de l'état :
function Counter() { const [count, setCount] = useState(0); return ( <div> <span className={count > 10 ? 'warning' : ''}> {count} </span> <button onClick={() => setCount(count + 1)}> +1 </button> </div> ); }
Vous ne dites pas “ajoute la classe warning”. Vous dites “si count > 10, la classe est warning”. React se charge du reste.
| Concept | PHP/jQuery | React |
|---|---|---|
| Où est la logique ? | Séparée (MVC) | Dans le composant |
| Comment modifier l'UI ? | Manipuler le DOM | Changer l'état |
| Flux de données | Bidirectionnel possible | Unidirectionnel |
| Paradigme | Impératif | Déclaratif |