Я переписую свій додаток, щоб використовувати Flux, і у мене виникла проблема з отриманням даних із магазинів. У мене багато компонентів, і вони багато гніздяться. Деякі з них великі ( Article
), інші маленькі та прості ( UserAvatar
,UserLink
).
Я боровся з тим, де в ієрархії компонентів мені слід читати дані з магазинів.
Я спробував два крайні підходи, жоден з яких мені не сподобався:
Усі компоненти сутності зчитують власні дані
Кожен компонент, якому потрібні деякі дані з магазину, отримує лише ідентифікатор сутності та отримує сутність самостійно.
Так , наприклад, Article
передається articleId
, UserAvatar
і UserLink
передаються userId
.
Цей підхід має кілька суттєвих недоліків (обговорюється у зразку коду).
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>
)
}
});
Недоліки цього підходу:
- Розчаровує наявність 100-ти компонентів, які потенційно підписуються на магазини;
- Це важко стежити за тим, як дані оновлюються і в якому порядку , оскільки кожен компонент витягує свої дані незалежно один від одного;
- Незважаючи на те, що у вас вже є сутність у стані, ви змушені передати її ідентифікатор дітям, які знову отримають його (або порушать узгодженість).
Всі дані зчитуються один раз на верхньому рівні та передаються компонентам
Коли я втомився відстежувати помилки, я намагався поставити всі дані, що отримують, на найвищий рівень. Однак це виявилося неможливим, оскільки для деяких суб’єктів у мене є кілька рівнів вкладеності.
Наприклад:
- A
Category
міститьUserAvatar
людей, які сприяють цій категорії; - У одного
Article
може бути декількаCategory
с.
Тому, якщо я хотів отримати всі дані з магазинів на рівні an Article
, мені потрібно було б:
- Отримати статтю з
ArticleStore
; - Отримати всі категорії статті з
CategoryStore
; - Окремо отримайте учасників кожної категорії
UserStore
; - Якимось чином передайте всі ці дані компонентам.
Ще більш засмучує те, що коли мені потрібна глибоко вкладена сутність, мені потрібно буде додавати код на кожен рівень вкладеності, щоб додатково передавати його.
Підводячи підсумки
Обидва підходи здаються недосконалими. Як вирішити цю проблему найелегантніше?
Мої цілі:
Магазини не повинні мати шаленої кількості передплатників. Дурно для кожного
UserLink
слухати,UserStore
якщо батьківські компоненти це вже роблять.Якщо батьківський компонент витягнув якийсь об’єкт із сховища (наприклад
user
), я не хочу, щоб будь-які вкладені компоненти мали знову його отримувати. Я повинен мати можливість передавати його через реквізит.Мені не потрібно отримувати всі сутності (включаючи відносини) на найвищому рівні, оскільки це ускладнить додавання або видалення відносин. Я не хочу вводити новий реквізит на всіх рівнях вкладеності кожного разу, коли вкладений об’єкт отримує нові відносини (наприклад, категорія отримує a
curator
).