Em um aplicativo Flux, deve haver apenas um Dispatcher. Todos os dados fluem através deste hub central. Ter um despachante único permite gerenciar todas as lojas. Isso se torna importante quando você precisa atualizar a Loja nº 1 e fazer com que a Loja 2 se atualize com base na Ação e no estado da Loja nº 1. O fluxo pressupõe que esta situação é uma eventualidade em uma aplicação grande. Idealmente, essa situação não precisaria acontecer, e os desenvolvedores devem se esforçar para evitar essa complexidade, se possível. Mas o Singleton Dispatcher está pronto para lidar com isso quando chegar a hora.
As lojas também são singletons. Eles devem permanecer o mais independentes e dissociados possível - um universo independente que pode ser consultado a partir de uma visão do controlador. O único caminho para a loja é através do retorno de chamada que ele registra no Dispatcher. A única saída é através das funções getter. As lojas também publicam um evento quando seu estado foi alterado, para que as Views do Controlador possam saber quando consultar o novo estado, usando os getters.
No seu aplicativo de exemplo, haveria um único PostStore
. Essa mesma loja pode gerenciar as postagens em uma "página" (pseudo-página) que é mais parecida com o Newsfeed do FB, onde as postagens aparecem de diferentes usuários. Seu domínio lógico é a lista de postagens e pode lidar com qualquer lista de postagens. Quando passamos de pseudo-página para pseudo-página, queremos reinicializar o estado da loja para refletir o novo estado. Também podemos querer armazenar em cache o estado anterior em localStorage como uma otimização para ir e voltar entre pseudo-páginas, mas minha inclinação seria configurar um PageStore
que aguarde todas as outras lojas, gerenciando o relacionamento com localStorage para todas as lojas em a pseudo-página e atualiza seu próprio estado. Observe que isso PageStore
não armazenaria nada sobre as postagens - esse é o domínio doPostStore
. Simplesmente saberia se uma pseudo-página específica foi armazenada em cache ou não, porque as pseudo-páginas são seu domínio.
O PostStore
teria um initialize()
método. Esse método sempre limpa o estado antigo, mesmo que seja a primeira inicialização, e cria o estado com base nos dados recebidos pela Ação, por meio do Dispatcher. Mover de uma pseudo-página para outra provavelmente envolveria uma PAGE_UPDATE
ação, o que desencadearia a invocação de initialize()
. Há detalhes a serem trabalhados para recuperar dados do cache local, recuperar dados do servidor, renderização otimista e estados de erro XHR, mas essa é a ideia geral.
Se uma pseudo-página específica não precisar de todos os armazenamentos no aplicativo, não tenho muita certeza de que exista algum motivo para destruir os não utilizados, além de restrições de memória. Mas as lojas normalmente não consomem muita memória. Você só precisa remover os ouvintes de eventos nas visualizações de controlador que estão destruindo. Isso é feito no componentWillUnmount()
método React .
UserListStore
, com todos os usuários relevantes nela. E cada usuário teria alguns sinalizadores booleanos descrevendo o relacionamento com o perfil de usuário atual. Algo como{ follower: true, followed: false }
, por exemplo. Os métodosgetFolloweds()
egetFollowers()
recuperariam os diferentes conjuntos de usuários necessários para a interface do usuário.(Nota: usei a sintaxe ES6 usando a opção JSX Harmony.)
Como exercício, escrevi um aplicativo Flux de amostra que permite navegar
Github users
e reposicionar.É baseado na resposta de fisherwebdev, mas também reflete uma abordagem que eu uso para normalizar as respostas da API.
Consegui documentar algumas abordagens que tentei enquanto aprendia o Flux.
Tentei mantê-lo próximo ao mundo real (paginação, nenhuma API localStorage falsa).
Existem alguns bits aqui nos quais eu estava especialmente interessado:
switch
com ações ;Como classifico lojas
Tentei evitar parte da duplicação que já vi em outro exemplo do Flux, especificamente nas lojas. Achei útil dividir logicamente o Stores em três categorias:
Os armazenamentos de conteúdo mantêm todas as entidades de aplicativos. Tudo o que possui um ID precisa de seu próprio armazenamento de conteúdo. Os componentes que processam itens individuais solicitam novos dados aos armazenamentos de conteúdo.
Os armazenamentos de conteúdo coletam seus objetos de todas as ações do servidor. Por exemplo,
UserStore
olhaaction.response.entities.users
, se existir , independentemente de qual a ação disparada. Não há necessidade de aswitch
. O Normalizr facilita o nivelamento de qualquer resposta da API para esse formato.Os armazenamentos de lista acompanham os IDs de entidades que aparecem em alguma lista global (por exemplo, "feed", "suas notificações"). Neste projeto, eu não tenho essas lojas, mas pensei em mencioná-las de qualquer maneira. Eles lidam com paginação.
Eles normalmente respondem a apenas algumas acções (por exemplo
REQUEST_FEED
,REQUEST_FEED_SUCCESS
,REQUEST_FEED_ERROR
).Os Armazéns de listas indexados são como os Armazéns de listas, mas definem o relacionamento um para muitos. Por exemplo, “assinantes de usuários”, “observadores de estrelas do repositório”, “repositórios de usuários”. Eles também lidam com paginação.
Eles também normalmente respondem a apenas algumas acções (por exemplo
REQUEST_USER_REPOS
,REQUEST_USER_REPOS_SUCCESS
,REQUEST_USER_REPOS_ERROR
).Na maioria dos aplicativos sociais, você terá muitos deles e deseja criar rapidamente mais um.
Nota: estas não são classes reais ou algo assim; é assim que eu gosto de pensar nas lojas. Eu fiz alguns ajudantes embora.
StoreUtils
createStore
Este método fornece a loja mais básica:
Eu o uso para criar todas as lojas.
isInBag
,mergeIntoBag
Pequenos ajudantes úteis para armazenamentos de conteúdo.
PaginatedList
Armazena o estado de paginação e aplica certas asserções (não é possível buscar a página durante a busca, etc.).
PaginatedStoreUtils
createListStore
,createIndexedListStore
,createListActionHandler
Facilita a criação dos armazenamentos de listas indexadas, fornecendo métodos padronizados e manipulação de ações:
createStoreMixin
Um mixin que permite que os componentes sintonizem-se nas lojas em que estão interessados, por exemplo
mixins: [createStoreMixin(UserStore)]
.fonte
Portanto, no Reflux, o conceito de Dispatcher é removido e você só precisa pensar em termos de fluxo de dados através de ações e lojas. Ou seja,
Cada seta aqui modela como o fluxo de dados é escutado, o que, por sua vez, significa que os dados fluem na direção oposta. A figura real do fluxo de dados é esta:
No seu caso de uso, se eu entendi corretamente, precisamos de uma
openUserProfile
ação que inicie o perfil do usuário carregando e alternando a página e também de algumas postagens carregando ações que carregarão postagens quando a página de perfil do usuário for aberta e durante o evento de rolagem infinita. Então, eu imagino que temos os seguintes armazenamentos de dados no aplicativo:No Reflux, você o configuraria assim:
As ações
O armazenamento de páginas
O repositório de perfis de usuário
A loja de postagens
Os componentes
Suponho que você tenha um componente para a exibição de página inteira, a página de perfil de usuário e a lista de postagens. É necessário conectar o seguinte:
Action.openUserProfile
ID correto durante o evento de clique.currentPageStore
saber para qual página alternar.currentUserProfileStore
saber quais dados do perfil do usuário mostrarcurrentPostsStore
para receber as postagens carregadasAction.loadMorePosts
.E isso deve ser praticamente isso.
fonte