Piszę ponownie moją aplikację, aby korzystała z Flux i mam problem z pobieraniem danych ze Sklepów. Mam dużo komponentów i dużo się zagnieżdżają. Niektóre z nich są duże ( Article
), inne małe i proste ( UserAvatar
, UserLink
).
Zmagałem się z tym, gdzie w hierarchii komponentów powinienem czytać dane ze Sklepów.
Wypróbowałem dwa ekstremalne podejścia, z których żadnego nie lubiłem:
Wszystkie komponenty jednostki odczytują własne dane
Każdy składnik, który potrzebuje niektórych danych ze sklepu, otrzymuje tylko identyfikator jednostki i samodzielnie pobiera jednostkę.
Na przykład, Article
jest przekazywana articleId
, UserAvatar
i UserLink
są przekazywane userId
.
Takie podejście ma kilka istotnych wad (omówionych w przykładowym kodzie).
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>
)
}
});
Wady tego podejścia:
- To frustrujące, że setki komponentów potencjalnie subskrybują Sklepy;
- To trudno śledzić, jak dane są aktualizowane i w jakiej kolejności , ponieważ każdy komponent pobiera swoje dane niezależnie;
- Nawet jeśli możesz już mieć jednostkę w stanie, jesteś zmuszony przekazać jej identyfikator dzieciom, które odzyskają go ponownie (lub zerwą spójność).
Wszystkie dane są odczytywane raz na najwyższym poziomie i przekazywane do komponentów
Kiedy byłem zmęczony śledzeniem błędów, próbowałem umieścić wszystkie dane na najwyższym poziomie. Okazało się to jednak niemożliwe, ponieważ dla niektórych podmiotów mam kilka poziomów zagnieżdżenia.
Na przykład:
- A
Category
zawieraUserAvatar
s osób, które współtworzą tę kategorię; Article
Może mieć kilkaCategory
s.
Dlatego gdybym chciał pobrać wszystkie dane ze Sklepów na poziomie an Article
, musiałbym:
- Pobierz artykuł z
ArticleStore
; - Pobierz wszystkie kategorie artykułów z
CategoryStore
; - Oddzielnie pobierz kontrybutorów każdej kategorii z
UserStore
; - W jakiś sposób przekazuje wszystkie te dane do komponentów.
Jeszcze bardziej frustrujące jest to, że ilekroć potrzebuję głęboko zagnieżdżonej jednostki, musiałbym dodać kod do każdego poziomu zagnieżdżenia, aby dodatkowo go przekazać.
Podsumowując
Oba podejścia wydają się wadliwe. Jak najbardziej elegancko rozwiązać ten problem?
Moje cele:
Sklepy nie powinny mieć szalonej liczby subskrybentów. To głupie, że każdy
UserLink
słucha,UserStore
jeśli komponenty nadrzędne już to robią.Jeśli komponent nadrzędny pobrał jakiś obiekt ze sklepu (np.
user
), Nie chcę, aby zagnieżdżone komponenty musiały pobierać go ponownie. Powinienem być w stanie przekazać to przez rekwizyty.Nie powinienem musieć pobierać wszystkich jednostek (w tym relacji) na najwyższym poziomie, ponieważ skomplikowałoby to dodawanie lub usuwanie relacji. Nie chcę wprowadzać nowych rekwizytów na wszystkich poziomach zagnieżdżenia za każdym razem, gdy zagnieżdżona encja otrzymuje nową relację (np. Kategoria otrzymuje a
curator
).