Redux - várias lojas, por que não?

221

Como observação: li os documentos do Redux (Baobab também) e fiz uma boa parte do Google e dos testes.

Por que é tão fortemente sugerido que um aplicativo Redux tenha apenas uma loja?

Entendo os prós / contras de uma configuração de loja única versus uma configuração de loja múltipla ( há muitas perguntas e respostas sobre SO neste assunto ).

Na IMO, essa decisão de arquitetura pertence aos desenvolvedores de aplicativos com base nas necessidades de seus projetos. Então, por que isso é tão fortemente sugerido para o Redux, quase a ponto de parecer obrigatório ( embora nada esteja nos impedindo de fazer várias lojas )?

EDIT: feedback após a conversão em loja única

Depois de alguns meses trabalhando com redux no que muitos considerariam um SPA complexo, posso dizer que a estrutura de uma única loja foi uma delícia pura de se trabalhar.

Alguns pontos que podem ajudar outras pessoas a entender por que uma loja única versus muitas lojas são uma questão discutível em muitos casos de uso:

  • é confiável : usamos seletores para percorrer o estado do aplicativo e obter informações relevantes ao contexto. Sabemos que todos os dados necessários estão em uma única loja. Evita todos os questionamentos sobre onde poderiam estar as questões estatais.
  • é rápido : atualmente, nossa loja possui cerca de 100 redutores, se não mais. Mesmo nessa contagem, apenas um punhado de redutores processa dados em um determinado envio, os outros retornam o estado anterior. O argumento de que uma loja enorme / complexa ( nbr de redutores ) é lenta é bastante discutível. Pelo menos não vimos nenhum problema de desempenho vindo daí.
  • amigável para depuração : embora esse seja o argumento mais convincente para usar o redux como um todo, ele também vale para loja única versus loja múltipla. Ao criar um aplicativo, você provavelmente terá erros de estado no processo ( erros do programador ), é normal. A PITA é quando esses erros levam horas para depurar. Graças à loja única ( e redux-logger ), nunca gastamos mais do que alguns minutos em qualquer problema de estado.

algumas dicas

O verdadeiro desafio na construção de sua loja redux é ao decidir como estruturá- la. Em primeiro lugar, porque mudar a estrutura no caminho é apenas uma grande dor. Em segundo lugar, porque determina em grande parte como você usará e consultará os dados do seu aplicativo para qualquer processo. Há muitas sugestões sobre como estruturar uma loja. No nosso caso, achamos o seguinte ideal:

{
  apis: {     // data from various services
    api1: {},
    api2: {},
    ...
  }, 
  components: {} // UI state data for each widget, component, you name it 
  session: {} // session-specific information
}

Espero que esse feedback ajude outras pessoas.

EDIT 2 - ferramentas úteis da loja

Para aqueles que se perguntam como gerenciar "facilmente" uma única loja , que pode se tornar rapidamente complexa. Existem ferramentas que ajudam a isolar as dependências / lógica estrutural da sua loja.

Existe o Normalizr que normaliza seus dados com base em um esquema. Em seguida, fornece uma interface para trabalhar com seus dados e buscar outras partes id, como um dicionário.

Não conhecendo a Normalizr na época, construí algo na mesma linha. O relational-json pega um esquema e retorna uma interface baseada em tabela ( um pouco como um banco de dados ). A vantagem do relational-json é que sua estrutura de dados faz referência dinâmica a outras partes de seus dados ( essencialmente, você pode atravessá-los em qualquer direção, assim como objetos JS normais ). Não é tão maduro quanto o Normalizr, mas estou usando-o com sucesso na produção há alguns meses.

Sebastien Daniel
fonte
4
Eu gosto da sua abordagem para a estrutura da loja que você está usando; no entanto, como você está lidando com o mapeamento de alterações de estado da API para as alterações de estado do componente? Por exemplo, digamos que recebo dados específicos do domínio da minha API, como isso se traduz em uma estrutura de dados genérica encontrada nos meus componentes?
Diniden
A decisão de como seus componentes mapeiam / usam os dados da loja depende de você. Embora eu ache que não entendi completamente sua pergunta, você poderia elaborar ou iniciar uma sessão de bate-papo?
Sebastien Daniel
2
Acho que a pergunta seria: seus componentes processam qualquer um do estado apis ou apenas processam o que é colocado no estado de componentes. Eu suspeitaria que, se você conseguiu renderizar apenas a partir do estado do componente, encontrou uma excelente maneira de tornar seus componentes e contêineres altamente reutilizáveis, mesmo na presença de dados específicos do domínio. Se seus componentes estão renderizando parcialmente do estado da API E do estado do componente, acho que você está utilizando Containers específicos do domínio para mapear os dados nas APIs para listas e primitivas genéricas que seus componentes entendem.
Diniden
2
Uso o Redux em conjunto com seletores, que são basicamente mapeadores de dados puramente funcionalizados e memorizados. Cada componente "reage" para armazenar atualizações e, se uma alteração for relevante para ele, "seleciona" os dados e renderiza de acordo. Portanto, sim, os componentes são renderizados SOMENTE com base no que é importante para eles. Mas isso não é apenas por causa do Redux ou da estrutura da loja. Isso se deve à combinação de um armazenamento de dados Imutável, um teste de comparação referencial para alterações de dados e um seletor puro que busca os dados que o componente precisa, no formato que ele precisa.
Sebastien Daniel
Hey @SebastienDaniel, você poderia mostrar um exemplo de como você está implementando a verificação de que cada componente faz para saber se a alteração na atualização da loja é relevante para ele? Quero dizer, se você está usando algum tipo de padrão genérico ... ou se, em todos os casos específicos, está verificando se os dados específicos do componente foram alterados.
John Bernardsson

Respostas:

232

Existem casos extremos quando você pode usar vários armazenamentos (por exemplo, se você tiver problemas de desempenho com a atualização de listas de milhares de itens que estão na tela ao mesmo tempo várias vezes por segundo). Dito isto, é uma exceção e, na maioria dos aplicativos, você nunca precisa de mais do que uma única loja.

Por que enfatizamos isso nos documentos? Como a maioria das pessoas provenientes do fundo do Flux assumirá que várias lojas são a solução para tornar o código de atualização modular. No entanto, o Redux tem uma solução diferente para isso: composição do redutor.

Ter vários redutores que são divididos em uma árvore redutora é como manter as atualizações modulares no Redux. Se você não reconhecer isso e procurar várias lojas sem entender completamente a composição do redutor primeiro, perderá muitos benefícios da arquitetura de loja única do Redux:

  • O uso da composição do redutor facilita a implementação de "atualizações dependentes" a la waitForno Flux, escrevendo um redutor chamando manualmente outros redutores com informações adicionais e em uma ordem específica.

  • Com uma única loja, é muito fácil persistir, hidratar e ler o estado. A renderização do servidor e a pré-busca de dados são triviais porque há apenas um armazenamento de dados que precisa ser preenchido e reidratado no cliente, e o JSON pode descrever seu conteúdo sem se preocupar com o ID ou nome da loja.

  • Uma única loja possibilita os recursos de viagem no tempo do Redux DevTools. Também facilita extensões da comunidade como redux-undo ou redux-optimist, porque operam no nível do redutor. Esses "aprimoradores redutores" não podem ser escritos para lojas.

  • Uma única loja garante que as assinaturas sejam chamadas somente após o processamento da expedição. Ou seja, quando os ouvintes são notificados, o estado já está totalmente atualizado. Em muitas lojas, não existem tais garantias. Essa é uma das razões pelas quais o Flux precisa da waitFormuleta. Com uma única loja, isso não é um problema que você vê em primeiro lugar.

  • Acima de tudo, várias lojas são desnecessárias no Redux (exceto casos de borda de desempenho com os quais você deve criar um perfil primeiro). Tornamos isso um ponto importante na documentação para que você seja incentivado a aprender a composição do redutor e outros padrões de Redux, em vez de usar o Redux como se fosse o Flux e perder seus benefícios.

Dan Abramov
fonte
11
Admito que não entendi todas as vantagens / necessidades da composição do redutor. Graças à sua resposta, fiz mais algumas leituras e um exemplo (TodoMVC, novamente). Com um exemplo tão pequeno, era difícil entender a melhoria real fornecida pela composição do redutor. No entanto, com um pouco de reflexão, em larga escala, o ganho é (agora) óbvio. Mais uma vez obrigado, ótima resposta!
Sebastien Daniel
4
@Sebastien O exemplo do "carrinho de compras" é melhor para isso, eu acho.
111115 Dan Abramov
3
Estou lentamente implementando o redux em um aplicativo tradicional (não SPA). Estou usando repositórios multilpe para cada "todo" convertido em uma implementação de reação / redux até que o aplicativo inteiro possa ser modificado para usar o mesmo repositório.
Paul Knopf
5
@DanAbramov Curioso, o que você acha de uma situação em que você tem seu "aplicativo" principal executando sua própria loja Redux e importando via npm um "aplicativo" independente que executa sua própria loja Redux separada. Por exemplo, se uma das outras equipes da sua empresa tiver algum tipo de serviço de mensagens com uma interface do usuário que você deseja acessar sem poluir sua loja com esses dados.
Natalia75
6
@ natlee75 "Alguns motivos válidos para o uso de várias lojas no Redux podem incluir: [...] Isolar um aplicativo Redux como um componente em um aplicativo maior; nesse caso, convém criar uma loja por instância do componente raiz." De redux.js.org/docs/FAQ.html#store-setup-multiple-stores
Kevin
24

Em alguns aplicativos empresariais muito grandes, com centenas ou milhares de redutores, geralmente é útil pensar em diferentes áreas do aplicativo como aplicativos totalmente separados. Nesses casos (onde realmente existem vários aplicativos que compartilham um nome de domínio), eu uso várias lojas.

Por exemplo, costumo tratar as seguintes áreas de funcionalidade comuns como aplicativos separados:

  • Admin
  • Análise / dados para painéis
  • Gerenciamento de faturamento e fluxos de compras
  • Equipe da conta corporativa / gerenciamento de permissão

Se alguma dessas coisas for pequena, mantenha-as como parte do aplicativo principal. Se eles crescerem muito (como algumas ferramentas de análise e gerenciamento de contas corporativas), divida-os.

A melhor maneira de gerenciar aplicativos muito grandes é tratá-los como uma composição de muitos aplicativos menores.

Se seu aplicativo for menor que ~ 50k LOC, provavelmente você deve ignorar esse conselho e seguir o conselho de Dan.

Se o seu aplicativo tiver mais de 1 milhão de LOC, você provavelmente deverá dividir miniaplicativos, mesmo se os mantiver em um repositório mono.

Eric Elliott
fonte
5

Essa decisão de arquitetura pertence aos desenvolvedores de aplicativos com base nas necessidades de seus projetos

Você está vivendo em seu próprio mundo. Estou me encontrando com pessoas que usam redux, porque é popular todos os dias. Você nem podia imaginar quantos projetos foram iniciados no reduxux sem nenhuma decisão. Eu odeio abordagens redux, mas tive que usá-lo, porque outros desenvolvedores não sabem mais nada. É apenas uma bolha épica inflada pelo facebook.

  • Não é confiável porque partes da loja não são isoladas.
  • É ineficiente porque você está clonando e atravessando o hash trie. Quando as mutações crescem aritmeticamente - a complexidade cresce geometricamente. Você não pode consertar isso refatorando quaisquer redutores, seletores, etc. Você precisa dividir sua tentativa.
  • Quando fica lento, ninguém quer dividi-lo em aplicativos separados com lojas separadas. Ninguém quer gastar dinheiro em refatoração. As pessoas geralmente estão convertendo alguns componentes inteligentes em despejo e é isso. Você sabe que futuro está esperando para desenvolvedores de redux? Eles vão manter esses infernos.
  • Não é amigável para depuração . É difícil depurar conexões entre partes praticamente isoladas da loja. É muito difícil até analisar a quantidade dessas conexões.

Vamos imaginar que você tenha várias lojas de redux. Você interromperá o fluxo de dados unidirecional. Você perceberá imediatamente quantas conexões entre lojas você possui. Você pode sofrer com essas conexões, lutando com depósitos circulares, etc.

Um único estoque imutável com fluxo unidirecional não é um elixir para todas as doenças. Se você não quiser manter a arquitetura do projeto, sofrerá assim mesmo.

puchu
fonte
Gostei do que você disse e aqui fiz perguntas relacionadas. Você se importaria de olhar para isso quando tiver algum tempo e compartilhar suas opiniões? A pergunta que fiz no Reddit, porque o SO não incentiva essas perguntas aqui.
Arup Rakshit 16/09
3

Vários armazenamentos podem ser úteis nos seguintes casos de uso 1. Se você tiver componentes grandes que são independentes entre si em termos de estrutura de dados, comportamento, contexto do aplicativo. O isolamento desses componentes facilita o gerenciamento de fluxo de dados e aplicativos. Também ajuda no desenvolvimento e manutenção independentes de seus componentes. 2. Problemas de desempenho: não é um caso de uso típico, mas se alguns de seus componentes estiverem atualizando com muita frequência e não tiver nenhum impacto sobre outros componentes, provavelmente você poderá procurar em lojas diferentes.

Para todos os outros casos, talvez você não precise ter vários repositórios. Como Dan diz, a criação de composições redutoras ponderadas pode ser a melhor solução.

newtonflash
fonte
Sua mensagem parece "use redux sempre, exceto em alguns casos" == "você não precisa da arquitetura do projeto, exceto em alguns casos". É muito próximo da realidade, estou feliz.
Puchu
2

por que não podemos usar várias lojas usando o redux ????

Isso não é necessário no Redux porque a separação entre domínios de dados já é alcançada dividindo um único redutor em redutores menores.


Posso ou devo criar várias lojas? Posso importar minha loja diretamente e usá-la nos componentes?

O padrão de fluxo original descreve ter várias "lojas" em um aplicativo, cada uma contendo uma área diferente de dados do domínio. Isso pode apresentar problemas como a necessidade de ter uma loja "waitFor" em outra loja para atualizar.

Isso não é necessário no Redux porque a separação entre domínios de dados já é alcançada dividindo um único redutor em redutores menores.

Como em várias outras perguntas, é possível criar várias lojas Redux distintas em uma página, mas o padrão pretendido é ter apenas uma loja. Ter um único repositório permite o uso do Redux DevTools, simplifica a persistência e a reidratação de dados e simplifica a lógica da assinatura.

Alguns motivos válidos para o uso de várias lojas no Redux podem incluir:

Solução de um problema de desempenho causado por atualizações muito frequentes de alguma parte do estado, quando confirmado pela criação de perfil do aplicativo. Isolando um aplicativo Redux como um componente em um aplicativo maior, nesse caso, convém criar um armazenamento por instância do componente raiz. No entanto, a criação de novas lojas não deve ser o seu primeiro instinto, especialmente se você tem experiência com o Flux. Tente a composição do redutor primeiro e use apenas vários repositórios se isso não resolver o seu problema.

Da mesma forma, embora você possa fazer referência à instância da sua loja importando-a diretamente, esse não é um padrão recomendado no Redux. Se você criar uma instância de loja e exportá-la de um módulo, ela se tornará um singleton. Isso significa que será mais difícil isolar um aplicativo Redux como componente de um aplicativo maior, se isso for necessário, ou ativar a renderização do servidor, porque no servidor você deseja criar instâncias de armazenamento separadas para cada solicitação.

doc oficial por redux

Rizo
fonte
1

Ter uma loja no Redux é realmente o que precisamos em muitos casos. Eu usei o Redux e o Flux e acredito que o Redux faz melhor o trabalho!

Não se esqueça que a loja está em um Objeto JavaScript, portanto, enquanto você tem apenas uma loja, ela pode ser facilmente estendida e reutilizada para mim, ter uma loja facilita muito o deslocamento usando as ferramentas de desenvolvimento Redux e não se confunde. grandes aplicações ...

Além disso, o conceito de uma loja está imitando o banco de dados para nós, uma fonte de verdade que você pode alterá-lo e acessá-lo na memória do navegador ...

Se o aplicativo inteiro for bem gerenciado, uma loja poderá ser suficiente para gerenciar todo o status do aplicativo ...

Alireza
fonte
3
Portanto, todos deveriam acreditar que uma única loja fará um trabalho melhor e ninguém poderia explicar o porquê. Isso me lembra alguma coisa ...
Puchu