- DĂ©veloppement de bibliothĂšques de composants sur React + Storybook
- Développement piloté par les tests dans JS ou comment commencer à aimer la programmation
- Migrer un vrai projet de Javascript vers Typescript - douleurs et fonctionnalités
Passons maintenant Ă l'article.

Quand j'ai commencĂ© Ă apprendre React, il y avait certaines choses que je ne comprenais pas. Et je pense que presque tous ceux qui connaissent React se posent les mĂȘmes questions. J'en suis sĂ»r parce que les gens crĂ©ent des bibliothĂšques entiĂšres pour rĂ©soudre des problĂšmes urgents. Voici deux questions principales qui semblent intĂ©resser presque tous les dĂ©veloppeurs React:
Comment un composant accĂšde-t-il aux informations (en particulier une variable d'Ă©tat) qui se trouvent dans un autre composant? Comment un composant appelle-t-il une fonction qui se trouve dans un autre composant?
Les développeurs JavaScript en général (et les développeurs React en particulier) se sont de plus en plus tournés vers l'écriture de fonctions dites pures ces derniers temps. Fonctions qui ne sont pas associées aux changements d'état. Fonctions qui n'ont pas besoin de connexions de base de données externes. Des fonctions indépendantes de ce qui se passe en dehors d'elles.
Bien sĂ»r, les fonctions pures sont un objectif noble. Mais si vous dĂ©veloppez une application plus ou moins complexe, vous ne pourrez pas nettoyer toutes les fonctions. Il viendra certainement un moment oĂč vous devrez crĂ©er au moins quelques composants qui sont en quelque sorte liĂ©s Ă d' autres composants. Essayer d'Ă©viter cela est ridicule. Ces connexions entre les composants sont appelĂ©es dĂ©pendances .
En général, les dépendances sont mauvaises et ne sont mieux utilisées qu'en cas de besoin. Mais là encore, si votre application a grandi, certains de ses composants dépendront nécessairement les uns des autres. Bien sûr, les développeurs de React le savent, ils ont donc compris comment amener un composant à transmettre des informations critiques, ou des fonctions, à ses composants enfants.
Approche standard: utiliser des accessoires pour transmettre des valeurs
Toute valeur d'Ă©tat peut ĂȘtre transmise Ă un autre composant via des accessoires. Toute fonction peut ĂȘtre transmise aux composants enfants via les mĂȘmes accessoires. C'est ainsi que les descendants savent quelles valeurs d'Ă©tat sont stockĂ©es dans l'arborescence et peuvent potentiellement appeler des actions dans les composants parents. Tout cela, bien sĂ»r, est bon. Mais les dĂ©veloppeurs de React sont prĂ©occupĂ©s par un problĂšme particulier.
La plupart des applications sont en couches. Dans les applications complexes, les structures peuvent ĂȘtre imbriquĂ©es trĂšs profondĂ©ment. L'architecture gĂ©nĂ©rale pourrait ressembler Ă ceci:
App
â fait rĂ©fĂ©rence Ă â ContentArea
ContentArea
â fait rĂ©fĂ©rence Ă â MainContentArea
MainContentArea
â fait rĂ©fĂ©rence Ă â MyDashboard
MyDashboard
â fait rĂ©fĂ©rence Ă â MyOpenTickets
MyOpenTickets
â fait rĂ©fĂ©rence Ă â TicketTable
TicketTable
â fait rĂ©fĂ©rence Ă une sĂ©quence â TicketRow
Chaque
TicketRow
â fait rĂ©fĂ©rence Ă âTicketDetail
ThĂ©oriquement, cette guirlande peut ĂȘtre enroulĂ©e pendant longtemps. Tous les composants font partie de l'ensemble. Plus prĂ©cisĂ©ment, une partie d'une hiĂ©rarchie. Mais ici, la question se pose:
le composant
TicketDetail
de l'exemple ci-dessus peut-il lire les valeurs d'état stockées ContentArea
? Ou. Un composant peut-il TicketDetail
appeler des fonctions qui se trouvent dans ContentArea
?
La rĂ©ponse aux deux questions est oui. En thĂ©orie, tous les descendants peuvent connaĂźtre toutes les variables stockĂ©es dans les composants parents. Ils peuvent Ă©galement appeler des fonctions ancĂȘtres - mais avec une grande mise en garde. Cela n'est possible que si ces valeurs (valeurs d'Ă©tat ou de fonction) sont explicitement passĂ©es aux descendants via des accessoires. Sinon, l'Ă©tat ou les valeurs de fonction du composant ne seront pas disponibles pour son composant enfant.
Dans les petites applications et utilitaires, cela ne joue pas un rĂŽle particulier. Par exemple, si un composant a
TicketDetail
besoin d'accéder aux variables d'état qui sont stockées dans TicketRow
, il suffit de faire en sorte que le composant TicketRow
â passe ces valeurs Ă son descendant â TicketDetail
via un ou plusieurs accessoires. Il en va de mĂȘme lorsqu'un composant TicketDetail
doit appeler une fonction qui se trouve dans TicketRow
. Component TicketRow
â passera cette fonction Ă son descendant â TicketDetail
via prop. Le mal de tĂȘte commence lorsqu'un composant situĂ© loin dans l'arborescence a besoin d'accĂ©der Ă l'Ă©tat ou Ă la fonction du composant en haut de la hiĂ©rarchie.
Pour résoudre ce problÚme dans React, les variables et les fonctions sont traditionnellement transmises à tous les niveaux. Mais cela encombre le code, prend des ressources et nécessite une planification sérieuse. Nous devrions passer des valeurs à de nombreux niveaux comme ceci:
ContentArea
â MainContentArea
â MyDashboard
â MyOpenTickets
â TicketTable
â TicketRow
â TicketDetail
C'est-Ă -dire que pour passer une variable d'Ă©tat de
ContentArea
Ă TicketDetail
, nous devons faire beaucoup de travail. Les dĂ©veloppeurs expĂ©rimentĂ©s comprennent qu'il existe une longue chaĂźne de valeurs et de fonctions qui passent comme accessoires Ă travers des niveaux intermĂ©diaires de composants. La solution est si lourde que j'ai mĂȘme abandonnĂ© l'apprentissage de React Ă plusieurs reprises Ă cause de cela.
Le monstre nommé Redux
Je ne suis pas le seul Ă penser que transmettre toutes les valeurs d'Ă©tat et toutes les fonctions communes aux composants via des accessoires est trĂšs peu pratique. Il est peu probable que vous trouviez une application React complexe qui ne soit pas fournie avec un outil de gestion d'Ă©tat. Il nâexiste pas si peu dâoutils de ce type. Personnellement, j'adore MobX. Malheureusement, Redux est considĂ©rĂ© comme le "standard de l'industrie".
Redux est une idée originale des créateurs du noyau React. Autrement dit, ils ont d'abord créé une merveilleuse bibliothÚque React. Mais ils ont tout de suite compris qu'il était presque impossible de gérer l'Etat avec ses moyens. S'ils n'avaient pas trouvé un moyen de résoudre les problÚmes inhérents à cette bibliothÚque (sinon géniale), beaucoup d'entre nous n'auraient jamais entendu parler de React.
Ils ont donc proposé Redux.
Si React est Mona Lisa, alors Redux est une moustache qui lui est attachée. Si vous utilisez Redux, vous devrez écrire une tonne de code standard dans presque tous les fichiers de projet. Le dépannage et la lecture du code deviennent un enfer. La logique métier est transférée dans la cour. Le code contient de la confusion et des hésitations.
Mais si les dĂ©veloppeurs ont le choix: React + Redux ou React sans aucun outil de gestion d'Ă©tat tiers , ils choisissent presque toujours React + Redux. Ătant donnĂ© que la bibliothĂšque Redux a Ă©tĂ© dĂ©veloppĂ©e par les auteurs principaux de React, elle est considĂ©rĂ©e comme une solution approuvĂ©e par dĂ©faut. Et la plupart des dĂ©veloppeurs prĂ©fĂšrent utiliser des solutions qui ont Ă©tĂ© tacitement approuvĂ©es comme celle-ci.
Bien sĂ»r, Redux crĂ©era tout un rĂ©seau de dĂ©pendancesdans votre application React. Mais, pour ĂȘtre honnĂȘte, tout outil de gestion dâĂtat gĂ©nĂ©rique fera de mĂȘme. L'outil de gestion d'Ă©tat est un rĂ©fĂ©rentiel partagĂ© de variables et de fonctions. Ces fonctions et variables peuvent ĂȘtre utilisĂ©es par tout composant ayant accĂšs au stockage partagĂ©. Cela prĂ©sente un inconvĂ©nient Ă©vident: tous les composants deviennent dĂ©pendants du stockage partagĂ©.
La plupart des développeurs React que je connais qui ont essayé de résister à l'utilisation de Redux ont finalement abandonné. (Parce que ... la résistance est inutile.) Je connais beaucoup de gens qui détestent immédiatement Redux. Mais quand ils ont été confrontés à un choix - Redux ou "nous trouverons un autre développeur React" - ils se sont jetésont accepté d'embrasser Redux comme partie intégrante de leur vie. C'est comme les impÎts. Comme un examen rectal. Comme aller chez le dentiste.
Réagir aux valeurs partagées dans React
Je suis trop tĂȘtu pour abandonner si facilement. AprĂšs avoir regardĂ© Redux, j'ai rĂ©alisĂ© que je devais chercher d'autres solutions. Je peux utiliser Redux. Et j'ai travaillĂ© dans des Ă©quipes qui utilisaient cette bibliothĂšque. En gĂ©nĂ©ral, je comprends ce qu'elle fait. Mais cela ne veut pas dire que j'aime Redux.
Comme je l'ai dit, alors qu'un outil de gestion d'état séparé est indispensable, MobX est environ ... un million de fois meilleur que Redux! Mais je suis tourmenté par une question plus sérieuse. Cela touche l'esprit collectif des développeurs de React:
pourquoi nous saisissons toujours d'abord d'un outil de gestion d'Ă©tat?
Lorsque j'ai commencé à développer avec React, j'ai passé de nombreuses nuits à chercher des solutions alternatives. Et j'ai trouvé un moyen que de nombreux développeurs React négligent, mais aucun d'entre eux ne peut dire pourquoi . Expliquera.
Imaginez que dans l'application hypothétique dont j'ai parlé ci-dessus, nous créons un fichier comme celui-ci:
// components.js
let components = {};
export default components;
Et c'est tout. Juste deux courtes lignes de code. Nous créons un objet vide - un bon vieil objet JS . Nous l'exportons par défaut avec
export default
.
Voyons maintenant à quoi pourrait ressembler le code à l'intérieur du composant
<
ContentArea>
:
// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';
export default class ContentArea extends React.Component {
constructor(props) {
super(props);
components.ContentArea = this;
}
consoleLog(value) {
console.log(value);
}
render() {
return <MainContentArea/>;
}
}
Pour la plupart, cela ressemble à un composant React basé sur des classes parfaitement normal. Nous avons une fonction simple
render()
qui accĂšde au composant suivant dans l'arborescence. Nous avons une petite fonction console.log()
qui imprime le résultat de l'exécution du code sur la console et un constructeur. Mais ... il y a quelques nuances dans le constructeur .
Au tout début, nous avons importé un objet simple
components
. Ensuite, dans le constructeur, nous avons ajouté une nouvelle propriété à l'objet components
avec le nom du composant React actuel ( this
). Dans cette propriété, nous faisons référence au composant this
. Désormais, chaque fois que nous accédons à l'objet composants, nous aurons un accÚs direct au composant <
ContentArea>
.
Voyons ce qui se passe en bas de la hiérarchie. Le composant
<
TicketDetail>
peut ĂȘtre comme ceci:
// ticket.detail.js
import components from './components';
import React from 'react';
export default class TicketDetail extends React.Component {
render() {
components.ContentArea.consoleLog('it works');
return <div>Here are the ticket details.</div>;
}
}
Voici ce qui se passe. Chaque fois que le composant
TicketDetail
est rendu consoleLog()
, la fonction stockée dans le composant sera appelée ContentArea
.
Notez que la fonction n'est
consoleLog()
pas transmise à travers toute la hiérarchie via les accessoires. En fait, la fonction n'est consoleLog()
transmise nulle part - ni nulle part - Ă aucun composant.
Et pourtant, il
TicketDetail
peut appeler la fonction consoleLog()
qui est stockée dans ContentArea
, car nous avons fait deux choses:
ContentArea
Une fois chargĂ©, le composant a ajoutĂ© un lien vers lui-mĂȘme vers l'objet partagĂ© des composants.TicketDetail
Une fois chargé, le composant importait un objet partagécomponents
, c'est-Ă -dire qu'il avait un accĂšs direct au composantContentArea
, malgré le fait que les propriétés n'étaientContentArea
pas transmises au composantTicketDetail
via des accessoires.
Cette approche ne fonctionne pas uniquement avec les fonctions / callbacks. Il peut ĂȘtre utilisĂ© pour interroger directement les valeurs des variables d'Ă©tat. Imaginons Ă quoi
<
ContentArea>
ressemble ceci:
// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';
export default class ContentArea extends React.Component {
constructor(props) {
super(props);
this.state = { reduxSucks:true };
components.ContentArea = this;
}
render() {
return <MainContentArea/>;
}
}
Ensuite, nous pouvons Ă©crire
<
TicketDetail>
comme ceci:
// ticket.detail.js
import components from './components';
import React from 'react';
export default class TicketDetail extends React.Component {
render() {
if (components.ContentArea.state.reduxSucks === true) {
console.log('Yep, Redux is da sux');
}
return <div>Here are the ticket details.</div>;
}
}
DĂ©sormais, chaque fois que le composant est rendu
<
TicketDetail
, il recherchera la valeur de la variable state.reduxSucks
dans <
ContentArea>
. Si la variable renvoie une valeur true
, la fonction console.log()
imprimera un message sur la console. Cela se produira mĂȘme si la valeur de la variable ContentArea.state.reduxSucks
n'a jamais Ă©tĂ© transmise dans l'arborescence - Ă aucun des composants - via des accessoires. Ainsi, avec un simple objet JS sous-jacent qui vit en dehors du cycle de vie standard de React, nous pouvons faire en sorte que tout descendant puisse lire les variables d'Ă©tat directement Ă partir de n'importe quel parent chargĂ© dans l'objet composants. On peut mĂȘme appeler des fonctions du composant parent dans son descendant.
La possibilité d'appeler une fonction directement dans les composants enfants signifie que nous pouvons modifier l'état des composants parents directement à partir de leurs enfants. Par exemple comme ça.
Tout d'abord, dans le composant,
<
ContentArea>
nous allons créer une fonction simple qui change la valeur d'une variable reduxSucks
.
// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';
export default class ContentArea extends React.Component {
constructor(props) {
super(props);
this.state = { reduxSucks:true };
components.ContentArea = this;
}
toggleReduxSucks() {
this.setState((previousState, props) => {
return { reduxSucks: !previousState.reduxSucks };
});
}
render() {
return <MainContentArea/>;
}
}
Ensuite, dans le composant,
<
TicketDetail>
nous appellerons cette méthode via l'objet components
:
// ticket.detail.js
import components from './components';
import React from 'react';
export default class TicketDetail extends React.Component {
render() {
if (components.ContentArea.state.reduxSucks === true) {
console.log('Yep, Redux is da sux');
}
return (
<>
<div>Here are the ticket details.</div>
<button onClick={() => components.ContentArea.toggleReduxSucks()}>Toggle reduxSucks</button>
</>
);
}
}
DĂ©sormais, aprĂšs chaque rendu d'un composant, l'
<
TicketDetail>
utilisateur pourra appuyer sur un bouton qui changera (basculera) la valeur de la variable ContentArea.state.reduxSucks
en temps rĂ©el, mĂȘme si la fonction ContentArea.toggleReduxSucks()
n'a jamais été transmise dans l'arborescence via des accessoires.
Avec cette approche, le composant parent peut appeler la fonction directement à partir de son enfant. Voici comment procéder. Le composant mis à jour
<
ContentArea>
ressemblera Ă ceci:
// content.area.js
import components from './components';
import MainContentArea from './main.content.area';
import React from 'react';
export default class ContentArea extends React.Component {
constructor(props) {
super(props);
this.state = { reduxSucks:true };
components.ContentArea = this;
}
toggleReduxSucks() {
this.setState((previousState, props) => {
return { reduxSucks: !previousState.reduxSucks };
});
components.TicketTable.incrementReduxSucksHasBeenToggledXTimes();
}
render() {
return <MainContentArea/>;
}
}
Ajoutons maintenant de la logique au composant
<
TicketTable>
. Comme ça:
// ticket.table.js
import components from './components';
import React from 'react';
import TicketRow from './ticket.row';
export default class TicketTable extends React.Component {
constructor(props) {
super(props);
this.state = { reduxSucksHasBeenToggledXTimes: 0 };
components.TicketTable = this;
}
incrementReduxSucksHasBeenToggledXTimes() {
this.setState((previousState, props) => {
return { reduxSucksHasBeenToggledXTimes: previousState.reduxSucksHasBeenToggledXTimes + 1};
});
}
render() {
const {reduxSucksHasBeenToggledXTimes} = this.state;
return (
<>
<div>The `reduxSucks` value has been toggled {reduxSucksHasBeenToggledXTimes} times</div>
<TicketRow data={dataForTicket1}/>
<TicketRow data={dataForTicket2}/>
<TicketRow data={dataForTicket3}/>
</>
);
}
}
En conséquence, le composant n'a
<
TicketDetail>
pas changé. Cela ressemble toujours à ceci:
// ticket.detail.js
import components from './components';
import React from 'react';
export default class TicketDetail extends React.Component {
render() {
if (components.ContentArea.state.reduxSucks === true) {
console.log('Yep, Redux is da sux');
}
return (
<>
<div>Here are the ticket details.</div>
<button onClick={() => components.ContentArea.toggleReduxSucks()}>Toggle reduxSucks</button>
</>
);
}
}
Avez-vous remarqué la bizarrerie associée à ces trois classes? Dans la hiérarchie de notre application
ContentArea
, il s'agit du composant parent pour TicketTable
, qui est le composant parent pour TicketDetail
. Cela signifie que lorsque nous montons un composant ContentArea
, il ne "connaĂźt" pas encore son existence TicketTable
. Et la fonction toggleReduxSucks()
Ă©crite en ContentArea
appelle implicitement la fonction enfant:. Il
incrementReduxSucksHasBeenToggledXTimes()
s'avĂšre que le code ne fonctionnera pas , non?
Mais non.
Regardez. Nous avons créé plusieurs niveaux dans l'application, et il n'y a qu'une seule façon d'appeler la fonction
toggleReduxSucks()
. Comme ça.
- Nous montons et rendons
ContentArea
. - Au cours de ce processus, une référence aux composants est chargée dans l'objet composants
ContentArea
. - Le résultat est monté et rendu
TicketTable
. - Au cours de ce processus, une référence aux composants est chargée dans l'objet composants
TicketTable
. - Le résultat est monté et rendu
TicketDetail
. - « reduxSucks» (Toggle reduxSucks).
- « reduxSucks».
-
toggleReduxSucks()
,ContentArea
. -
incrementReduxSucksHasBeenToggledXTimes()
TicketTable
. - , , « reduxSucks»,
TicketTable
components.toggleReduxSucks()
ContentArea
incrementReduxSucksHasBeenToggledXTimes()
,TicketTable
, components.
Il s'avÚre que la hiérarchie de notre application nous permet d'ajouter un
ContentArea
algorithme au composant qui appellera une fonction à partir du composant enfant, malgré le fait que le composant ContentArea
ne connaissait pas l'existence du composant lors de son montageTicketTable
.
Outils de gestion de patrimoine - Dump
Comme je l'ai expliqué, je suis profondément convaincu que Redux n'est pas à la hauteur de MobX. Et quand j'ai le privilÚge de travailler sur un projet à partir de zéro (malheureusement pas souvent), je fais toujours campagne pour MobX. Pas pour Redux. Mais lorsque je développe mes propres applications , j'utilise rarement des outils de gestion d'état tiers - presque jamais . Au lieu de cela, je mets simplement en cache des objets / composants chaque fois que possible. Et si cette approche ne fonctionne pas, je reviens souvent à la solution par défaut dans React, c'est-à -dire que je ne fais que passer des fonctions / variables d'état via des accessoires.
"ProblĂšmes" connus avec cette approche
Je suis bien conscient que mon idée de mettre en cache l'objet sous-jacent n'est
components
pas toujours adaptée pour résoudre les problÚmes d'état / de fonction partagés. Parfois, cette approche peut ... jouer une blague cruelle . Ou cela pourrait ne pas fonctionner du tout . Voici quelque chose à garder à l'esprit.
- Cela fonctionne mieux avec les célibataires .
Par exemple, dans notre hiérarchie, le composant <TicketTable> contient des composants <TicketRow> avec une relation zéro à plusieurs. Si vous souhaitez mettre en cache la référence à chaque composant potentiel dans les composants <TicketRow> (et leurs composants enfants <TicketDetail>) dans le cache des composants, vous devez les stocker dans un tableau, ce qui peut devenir délicat. J'ai toujours évité cela. - components , / , components. .
, . , , . / , , components. - ,
components
, (setState()
),setState()
, .
Maintenant que j'ai expliquĂ© mon approche et certaines de ses limites, je dois vous prĂ©venir. Depuis que j'ai dĂ©couvert cette approche, je la partage avec des personnes qui se considĂšrent comme des dĂ©veloppeurs React professionnels. A chaque fois, ils rĂ©pondent la mĂȘme chose:
Hmm ... Ne fais pas ça. Ils froncent les sourcils et agissent comme si je venais de gĂącher l'air. Quelque chose dans mon approche leur semble ... faux . Et en mĂȘme temps, personne ne m'a encore expliquĂ©, sur la base de sa riche expĂ©rience pratique, ce qui ne va pas exactement. C'est juste que tout le monde considĂšre mon approche ... comme un blasphĂšme .
Par consĂ©quent, mĂȘme si vous aimez cette approche ou si vous la trouvez pratique dans certaines situations, je ne recommande pasparlez-en lors d'un entretien si vous souhaitez dĂ©crocher un emploi de dĂ©veloppeur React. Je pense que mĂȘme en parlant Ă d'autres dĂ©veloppeurs React, il faut rĂ©flĂ©chir un million de fois avant de parler de cette mĂ©thode, ou peut-ĂȘtre qu'il vaut mieux ne rien dire du tout.
J'ai trouvĂ© que les dĂ©veloppeurs JS - et les dĂ©veloppeurs React en particulier - peuvent ĂȘtre trop catĂ©goriques . Parfois, ils expliquent pourquoi l'approche A est «mauvaise» et l'approche B est «juste». Mais dans la plupart des cas, ils regardent simplement un morceau de code et le dĂ©clarent «mauvais», mĂȘme s'ils ne peuvent pas eux-mĂȘmes expliquer pourquoi.
Alors, pourquoi cette approche est-elle si ennuyeuse pour les développeurs React?
Comme je l'ai dit, aucun de mes collĂšgues ne pouvait raisonnablement expliquer pourquoi ma mĂ©thode est mauvaise. Et si quelqu'un est prĂȘt Ă m'honorer avec une rĂ©ponse, c'est gĂ©nĂ©ralement l'une des excuses suivantes (il y en a peu).
- , .
.... , , Redux ( MobX, ) / React-. , . â . , /, . : ,components
. , /components
, / , components. /,components
, components . , , . , , Redux, MobX, - . - React « ». ⊠.
⊠. ? , . â - « » « », , , . React, . , . . « », . , React 100 %, ( ) , .
, ?
J'ai écrit ce post parce que j'utilise cette approche depuis des années (dans des projets personnels). Et cela fonctionne trÚs bien . Mais chaque fois que je sors de ma bulle personnelle et que j'essaye d'avoir une conversation intelligente sur cette approche avec d'autres développeurs React tiers , je ne rencontre que des déclarations catégoriques et des jugements idiots sur les «normes de l'industrie».
Cette approche est- elle vraiment mauvaise ? Eh bien, vraiment. Je veux savoir. S'il s'agit bien d'un «anti-modĂšle», je serai extrĂȘmement reconnaissant Ă ceux qui justifieront son inexactitude. La rĂ©ponse «je ne suis pas habituĂ© Ă cela» ne me conviendra pas. Non, je ne suis pas coincĂ© avec cette mĂ©thode. Je ne dis pas que c'est une panacĂ©e pour les dĂ©veloppeurs React. Et j'avoue que cela ne fonctionne pas pour toutes les situations. Mais peut-ĂȘtrequelqu'un peut-il m'expliquer ce qui ne va pas avec ça?
Je veux vraiment connaĂźtre votre opinion Ă ce sujet - mĂȘme si vous me faites exploser en mille morceaux.