Sto riscrivendo la mia app per utilizzare Flux e ho un problema con il recupero dei dati dagli Store. Ho molti componenti e si annidano molto. Alcuni di loro sono grandi ( Article
), altri piccoli e semplici ( UserAvatar
, UserLink
).
Ho lottato con dove nella gerarchia dei componenti dovrei leggere i dati dai negozi.
Ho provato due approcci estremi, nessuno dei quali mi è piaciuto abbastanza:
Tutti i componenti dell'entità leggono i propri dati
Ogni componente che necessita di alcuni dati da Store riceve solo l'ID entità e recupera l'entità da sola.
Ad esempio, Article
è passato articleId
, UserAvatar
e UserLink
sono passati userId
.
Questo approccio ha diversi svantaggi significativi (discussi nell'esempio di codice).
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>
)
}
});
Aspetti negativi di questo approccio:
- È frustrante avere 100 componenti potenzialmente iscritti a Stores;
- È difficile tenere traccia di come i dati vengono aggiornati e in quale ordine perché ogni componente recupera i propri dati in modo indipendente;
- Anche se potresti già avere un'entità nello stato, sei costretto a passare il suo ID ai bambini, che lo recupereranno di nuovo (oppure romperanno la coerenza).
Tutti i dati vengono letti una volta al livello superiore e passati ai componenti
Quando ero stanco di rintracciare i bug, ho provato a mettere tutti i dati recuperati al livello più alto. Ciò, tuttavia, si è rivelato impossibile perché per alcune entità ho diversi livelli di nidificazione.
Per esempio:
- A
Category
contieneUserAvatar
s di persone che contribuiscono a quella categoria; - An
Article
può avere diversi messaggiCategory
.
Pertanto, se volessi recuperare tutti i dati dagli Store a livello di un Article
, avrei bisogno di:
- Recupera l'articolo da
ArticleStore
; - Recupera tutte le categorie di articoli da
CategoryStore
; - Recupera separatamente i contributori di ciascuna categoria da
UserStore
; - In qualche modo passa tutti quei dati ai componenti.
Ancora più frustrante, ogni volta che ho bisogno di un'entità profondamente annidata, avrei bisogno di aggiungere codice a ogni livello di annidamento per trasmetterlo ulteriormente.
Riassumendo
Entrambi gli approcci sembrano imperfetti. Come risolvo questo problema nel modo più elegante?
I miei obiettivi:
I negozi non dovrebbero avere un numero folle di abbonati. È stupido per ciascuno
UserLink
ascoltareUserStore
se i componenti principali lo fanno già.Se il componente padre ha recuperato un oggetto dall'archivio (ad esempio
user
), non voglio che alcun componente annidato debba recuperarlo di nuovo. Dovrei essere in grado di passarlo tramite oggetti di scena.Non dovrei dover recuperare tutte le entità (comprese le relazioni) al livello superiore perché complicherebbe l'aggiunta o la rimozione delle relazioni. Non voglio introdurre nuovi oggetti di scena a tutti i livelli di nidificazione ogni volta che un'entità annidata ottiene una nuova relazione (ad esempio, la categoria ottiene una
curator
).