Estou reescrevendo meu aplicativo para usar o Flux e tenho um problema com a recuperação de dados do Stores. Tenho muitos componentes e eles se aninham muito. Alguns deles são grandes ( Article
), alguns são pequenos e simples ( UserAvatar
, UserLink
).
Tenho lutado para saber onde na hierarquia de componentes devo ler os dados do Stores.
Tentei duas abordagens extremas, nenhuma das quais gostei muito:
Todos os componentes da entidade leem seus próprios dados
Cada componente que precisa de alguns dados do Store recebe apenas o ID da entidade e recupera a entidade por conta própria.
Por exemplo, Article
é passado articleId
, UserAvatar
e UserLink
são passados userId
.
Essa abordagem tem várias desvantagens significativas (discutidas no exemplo de código).
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>
)
}
});
As desvantagens dessa abordagem:
- É frustrante ter componentes 100s potencialmente assinando lojas;
- É difícil controlar como os dados são atualizados e em que ordem, porque cada componente recupera seus dados independentemente;
- Mesmo que você já tenha uma entidade no estado, você é forçado a passar seu ID para os filhos, que irão recuperá-lo novamente (ou então quebrar a consistência).
Todos os dados são lidos uma vez no nível superior e passados para os componentes
Quando me cansei de rastrear bugs, tentei colocar todos os dados recuperados no nível superior. Isso, entretanto, provou ser impossível porque para algumas entidades eu tenho vários níveis de aninhamento.
Por exemplo:
- A
Category
contémUserAvatar
s de pessoas que contribuem para essa categoria; - Um
Article
pode ter váriosCategory
s.
Portanto, se eu quisesse recuperar todos os dados do Stores no nível de um Article
, precisaria:
- Recuperar artigo de
ArticleStore
; - Recupere todas as categorias de artigos de
CategoryStore
; - Recupere separadamente os colaboradores de cada categoria
UserStore
; - De alguma forma, passe todos esses dados para os componentes.
Ainda mais frustrante, sempre que preciso de uma entidade profundamente aninhada, preciso adicionar código a cada nível de aninhamento para transmiti-lo adicionalmente.
Resumindo
Ambas as abordagens parecem falhas. Como posso resolver este problema de forma mais elegante?
Meus objetivos:
As lojas não deveriam ter um número absurdo de assinantes. É estúpido para cada um
UserLink
ouvirUserStore
se os componentes pais já fazem isso.Se o componente pai recuperou algum objeto da loja (por exemplo
user
), não quero que nenhum componente aninhado precise buscá-lo novamente. Devo ser capaz de passar pelos adereços.Eu não deveria ter que buscar todas as entidades (incluindo relacionamentos) no nível superior, porque isso complicaria adicionar ou remover relacionamentos. Não quero introduzir novos adereços em todos os níveis de aninhamento cada vez que uma entidade aninhada obtém um novo relacionamento (por exemplo, a categoria obtém a
curator
).