Je réécris mon application pour utiliser Flux et j'ai un problème avec la récupération de données dans les magasins. J'ai beaucoup de composants et ils s'emboîtent beaucoup. Certains d'entre eux sont grands ( Article
), certains sont petits et simples ( UserAvatar
, UserLink
).
J'ai eu du mal à savoir où dans la hiérarchie des composants je devais lire les données des magasins.
J'ai essayé deux approches extrêmes, dont aucune ne m'a beaucoup plu:
Tous les composants d'entité lisent leurs propres données
Chaque composant qui a besoin de certaines données du Store reçoit uniquement l'ID d'entité et récupère l'entité par lui-même.
Par exemple, Article
est passé articleId
, UserAvatar
et UserLink
sont passés userId
.
Cette approche présente plusieurs inconvénients importants (décrits dans l'exemple de code).
var Article = React.createClass({
mixins: [createStoreMixin(ArticleStore)],
propTypes: {
articleId: PropTypes.number.isRequired
},
getStateFromStores() {
return {
article: ArticleStore.get(this.props.articleId);
}
},
render() {
var article = this.state.article,
userId = article.userId;
return (
<div>
<UserLink userId={userId}>
<UserAvatar userId={userId} />
</UserLink>
<h1>{article.title}</h1>
<p>{article.text}</p>
<p>Read more by <UserLink userId={userId} />.</p>
</div>
)
}
});
var UserAvatar = React.createClass({
mixins: [createStoreMixin(UserStore)],
propTypes: {
userId: PropTypes.number.isRequired
},
getStateFromStores() {
return {
user: UserStore.get(this.props.userId);
}
},
render() {
var user = this.state.user;
return (
<img src={user.thumbnailUrl} />
)
}
});
var UserLink = React.createClass({
mixins: [createStoreMixin(UserStore)],
propTypes: {
userId: PropTypes.number.isRequired
},
getStateFromStores() {
return {
user: UserStore.get(this.props.userId);
}
},
render() {
var user = this.state.user;
return (
<Link to='user' params={{ userId: this.props.userId }}>
{this.props.children || user.name}
</Link>
)
}
});
Inconvénients de cette approche:
- Il est frustrant d'avoir des centaines de composants potentiellement abonnés à des magasins;
- Il est difficile de savoir comment les données sont mises à jour et dans quel ordre, car chaque composant récupère ses données indépendamment;
- Même si vous avez peut-être déjà une entité dans l'état, vous êtes obligé de transmettre son ID aux enfants, qui la récupéreront à nouveau (ou bien rompront la cohérence).
Toutes les données sont lues une fois au niveau supérieur et transmises aux composants
Quand j'étais fatigué de traquer les bogues, j'ai essayé de mettre toutes les données récupérées au plus haut niveau. Cela s'est toutefois avéré impossible car pour certaines entités, j'ai plusieurs niveaux d'imbrication.
Par exemple:
- A
Category
contientUserAvatar
des personnes qui contribuent à cette catégorie; - Un
Article
peut avoir plusieursCategory
s.
Par conséquent, si je voulais récupérer toutes les données des magasins au niveau d'un Article
, j'aurais besoin de:
- Récupérer l'article de
ArticleStore
; - Récupérez toutes les catégories d'articles à partir de
CategoryStore
; - Récupérez séparément les contributeurs de chaque catégorie
UserStore
; - Transmettez en quelque sorte toutes ces données aux composants.
Encore plus frustrant, chaque fois que j'ai besoin d'une entité profondément imbriquée, je devrais ajouter du code à chaque niveau d'imbrication pour le transmettre en plus.
Résumer
Les deux approches semblent imparfaites. Comment résoudre ce problème de la manière la plus élégante?
Mes objectifs:
Les magasins ne devraient pas avoir un nombre insensé d'abonnés. C'est stupide pour chacun
UserLink
d'écouterUserStore
si les composants parents le font déjà.Si le composant parent a récupéré un objet du magasin (par exemple
user
), je ne veux pas qu'un composant imbriqué doive le récupérer à nouveau. Je devrais pouvoir le transmettre via des accessoires.Je ne devrais pas avoir à récupérer toutes les entités (y compris les relations) au niveau supérieur car cela compliquerait l'ajout ou la suppression de relations. Je ne veux pas introduire de nouveaux accessoires à tous les niveaux d'imbrication chaque fois qu'une entité imbriquée obtient une nouvelle relation (par exemple, la catégorie obtient un
curator
).