Redux: Questão: Como escolher entre a loja de Redux e o estado de React?

Criado em 27 jan. 2016  ·  26Comentários  ·  Fonte: reduxjs/redux

question

Comentários muito úteis

Use React para o estado efêmero que não importa para o aplicativo globalmente e não sofre mutação de maneiras complexas. Por exemplo, uma alternância em algum elemento da IU, um estado de entrada de formulário. Use Redux para o estado que importa globalmente ou é alterado de maneiras complexas. Por exemplo, usuários em cache ou um post draft.

Às vezes, você vai querer passar do estado Redux para o estado React (quando armazenar algo no Redux fica complicado) ou o contrário (quando mais componentes precisam ter acesso a algum estado que costumava ser local).

A regra é: faça o que for menos estranho.

Todos 26 comentários

Use React para o estado efêmero que não importa para o aplicativo globalmente e não sofre mutação de maneiras complexas. Por exemplo, uma alternância em algum elemento da IU, um estado de entrada de formulário. Use Redux para o estado que importa globalmente ou é alterado de maneiras complexas. Por exemplo, usuários em cache ou um post draft.

Às vezes, você vai querer passar do estado Redux para o estado React (quando armazenar algo no Redux fica complicado) ou o contrário (quando mais componentes precisam ter acesso a algum estado que costumava ser local).

A regra é: faça o que for menos estranho.

Para dados buscados por meio de solicitações de rede, sempre use lojas para oferecer suporte à renderização do lado do servidor (se você acredita que esse é o objetivo final), ou você não conseguirá reidratar.

Para que esses estados sejam ouvidos por dois ou mais containers, também deveriam estar nas lojas?

Concordo com @gaeron sobre a distinção entre efêmero e persistente. Mas eu realmente penso sobre isso em três categorias . Um é o estado da estado do estado de roteamento . Eu uso o termo "roteamento" porque é familiar às pessoas, mas abstraio isso para um estado de "seleção de visualização", pois acho que abrange melhor desktop, web e dispositivos móveis.

Agora você pode argumentar que este é o estado da interface do usuário porque é ele quem decide o que as pessoas veem (muito parecido com o estado das guias, por exemplo). Mas vejo duas distinções. A primeira é que o estado é serializado (ou seja, como um URL) e enviado a outras pessoas. Portanto, as coisas devem ir no estado de rota se você quiser que as pessoas possam fazer um "link direto" direto para aquele estado específico da IU . A segunda é que, em muitos casos, o estado inicial da rota ou uma mudança na rota aciona uma mudança no estado do aplicativo (ou seja, carregando os dados a serem visualizados). Obviamente, as ações na IU fazem a mesma coisa. Mas a distinção que faço é que você pode (e deve) ter o estado da rota sem qualquer visualização ou renderização precisamente para testar a "lógica do aplicativo" em torno das mudanças no estado da rota. E é porque a visualização e a renderização não precisam estar envolvidas que o torna parcialmente no estado do aplicativo, IMHO.

Como isso se relaciona com a questão de Redux vs. React para gerenciamento de estado? O estado do aplicativo é o domínio do Redux e o estado da UI é o domínio do React. Mas o estado de roteamento deve (na minha opinião) ser gerenciado pelo Redux, embora possa ser visto como o estado da interface do usuário (veja os links embutidos para mais discussão sobre porque eu acho isso).

Para ser claro, o comentário de @gaearon sobre coisas que estão se movendo ainda se aplica. Mas acho útil distinguir esses casos diferentes.

O estado do aplicativo é o domínio do Redux e o estado da UI é o domínio do React.

Observe que eu não reivindico isso. Acho que não há problema em manter algum estado do aplicativo no React e algum estado da interface do usuário no Redux. Não acho que eles devam ser separados por domínios.

Do jeito que eu penso sobre isso, se você criar um aplicativo com Redux, adote a árvore de estado único. Coloque o estado da IU lá também. No entanto, se ficar tedioso e frustrante , não tenha medo de colocar um estado nos componentes. Meu ponto é que use árvore de estado único, a menos que seja estranho, e só faça isso quando simplificar as coisas para você, em vez de complicá-las. Essa é a única diretriz.

Em primeiro lugar, certamente não tive a intenção de colocar palavras na boca de

Em segundo lugar, concordo totalmente com @gaearon. Eu também acredito firmemente em uma abordagem de árvore de estado único. Quando falei sobre o estado da interface do usuário, eu tinha em mente coisas realmente menores (como qual é a guia atual selecionada) onde pode não ser realmente relevante para o estado do aplicativo (exatamente como @gaearon foi discutido).

Deixe-me esclarecer minha posição. Eu concordo que quase tudo deve estar no Redux , incluindo o estado da rota (como eu fiz em minha implementação TodoMVC com Redux e TypeScript .

Para componentes React, raramente uso o estado. Eu prefiro usar adereços para obter informações sobre o que renderizar e para obter fechamentos que posso invocar para acionar alterações externas ao meu componente. Existem algumas circunstâncias raras em que introduzo estado nos componentes apenas para tornar a vida mais fácil, mas tento evitá-lo. Eu espero que isso esclareça as coisas.

Acho que essa questão é muito subjetiva e complicada, então tomei uma decisão difícil com minha equipe hoje, não se preocupe:

  • para container não reutilizável, que tem conexão com Redux, basta colocar tudo na loja Redux, mesmo em estado de UI minúsculo como se um modal estivesse aberto, não use mais this.setState .
  • para componentes reutilizáveis, que não têm nada a ver com Redux, use o estado React.

E agora estamos implementando alguns auxiliares para tornar menos tedioso o gerenciamento de pequenos estados da IU.

@gaearon @ lionng429 @xogeny Alguma desvantagem dessa abordagem?

@inetfuture Eu tendo a ser um pouco mesquinho sobre o estado do aplicativo (redux) porque estou usando o TypeScript e defino um tipo para o estado do meu aplicativo até o fim. Dito isso, eu comecei a acontecer ao desenvolver bibliotecas de componentes para separar toda a manipulação de estado da renderização (consulte os links nos comentários anteriores para obter mais detalhes). Isso significa que, mesmo para componentes gerais que não são triviais, externalizo completamente o estado. Eu geralmente passo tudo pelos adereços (estados e fechamentos para manipular o estado). Dessa forma, posso conectá-lo facilmente ao estado do meu aplicativo. Parte disso é, sem dúvida, um artefato de usar TypeScript e não ser capaz de usar apenas combineReducers e connect para conectar coisas (e preservar as restrições de tipo pelo menos). Portanto, este provavelmente não é um ponto de vista representativo. Mas direi que por que você diz "basta colocar tudo na loja Redux", eu me preocuparia se você acabasse com uma pia de cozinha de estado. Acho que o fato de meu uso do TypeScript significar que é preciso algum esforço para expandir o estado do aplicativo não é necessariamente uma coisa ruim porque me força a decidir "eu realmente preciso disso?" em vez de deixar as coisas simplesmente se acumularem.

Como alternativa: o estado do componente local pode ser útil para entradas controladas que precisam de um tempo de atualização rápido, bem como para reduzir o número de ações reais acionadas. No meu protótipo atual, eu montei um HOC de edição de formulário que recebe o item atual sendo editado como um acessório. Ele também lida com eventos de alteração de entrada de formulário salvando o campo alterado em seu estado e, em seguida, chamando um criador de ação "EDIT_ITEM_ATTRIBUTE" depurado com as alterações locais WIP combinadas. O resultado é que os campos do formulário são atualizados imediatamente, porque apenas o próprio formulário está sendo renderizado novamente e muito menos ações são acionadas (como, se eu mantivesse 'A' pressionado por alguns segundos, apenas o valor 'AAAAAAAAAAAA' seria ser enviado como uma ação em vez de 'A', 'AA', etc).

Eu tenho o HOC como uma essência em https://gist.github.com/markerikson/554cab15d83fd994dfab , se alguém se importar.

De qualquer forma, o ponto é que o estado do componente e o estado da loja têm seus usos - você só precisa considerar seu caso de uso real.

Quanto aos componentes reutilizáveis, se eles forem grandes e complexos o suficiente, seria bastante compatível com o futuro ter seu estado no Redux, principalmente para rastreabilidade e reprodução para teste. Mas ainda existem algumas dúvidas sobre como exatamente essa reutilização de código deve ser arquitetada (componentes mais ações mais redutores).

Em nossos aplicativos, resolvemos esse problema no estilo de conexão. https://github.com/Babo-Ltd/redux-state

Raramente achei estranho armazenar estados no Redux. Gosto do poder que ele fornece, que no futuro posso fazer com que ele interaja com algum outro componente, se necessário.

A única coisa que vem à minha mente onde seria estranho é lidar com o estado dos elementos da forma, porque pode haver muitos deles. Nesse caso, uso uma biblioteca como redux-form .

Meu ponto é que use árvore de estado único, a menos que seja estranho, e só faça isso quando simplificar as coisas para você, em vez de complicá-las. Essa é a única diretriz

@gaearon , você gostaria de compartilhar suas experiências sobre como decidir quando ou como isso deve ser considerado _awkward_? por exemplo, você pode dar alguns cenários / exemplos típicos que você acha que são estranhos o suficiente se eles forem colocados no átomo de estado do aplicativo? desde já, obrigado!

@idavollen , posso dar algumas:

  • um estado suspenso aberto / fechado, caso contrário, você teria que manter o controle de todos os componentes suspensos em sua loja
  • quando você está debulando uma mudança de <input> , você pode usar o estado para atualizar o valor instantaneamente (e você não está arriscando outros componentes a renderizar desnecessariamente) e atualizar a loja de uma maneira debelada

Basicamente, você deve usá-lo para o estado que não afeta outros componentes.

Eu tenho uma terceira situação a considerar, por exemplo, eu tenho um formulário (um componente de recipiente de reação que tem um cálculo caro no método de renderização) que consiste em muitas linhas com caixa de seleção precedida e um botão de envio. Quando o botão de envio é clicado, o formulário deve enviar as linhas cujas caixas de seleção estão marcadas, o que significa estados transitórios da caixa de seleção individual antes de enviar o formulário quando o usuário alterna para não é importante e não deve ser tratado como estado de componente e alternar a caixa de seleção não deve causar render () a ser chamado.

Por enquanto, eu não colocaria os estados da caixa de seleção no átomo de estado do aplicativo, nem no estado do componente local, ou seja, o componente de reação do formulário para evitar a chamada desnecessária de render () ao alternar a caixa de seleção, pelo contrário, um A variável de instância é preferível para manter as caixas de seleção marcadas, no entanto, é contra o padrão de reação.

Estou me perguntando qual é a melhor abordagem para gerenciar esses estados de caixas de seleção neste caso?

@idavollen essas caixas de seleção não são

Quão rápido é o Redux comparado ao estado dos componentes? Devo confiar no Redux para adereços de IU que são realmente sensíveis em termos de tempo entre o evento real e o processo de renderização? Eu tenho uma situação complicada em que usar o estado de componentes exigiria muita comunicação não tão direta. Qualquer ajuda neste assunto seria muito apreciada.

@tiberiumaxim Na minha experiência (desenvolvo aplicativos em

Cabe a você decidir qual estado vai no Redux, e o que permanece local para um componente. Você pode querer ler http://redux.js.org/docs/faq/OrganizingState.html#organizing -state-only-redux-state e http://redux.js.org/docs/faq/Performance. html # performance -scaling para algumas informações relacionadas.

@deowk obrigado por compartilhar seu conhecimento sobre o assunto desempenho, pensei o mesmo, mas precisava de confirmação.
Além disso, @markerikson obrigado pelos links, vou dar uma olhada neles mais uma vez.

Não tenho certeza se alguém mencionou isso explicitamente, mas o estado do componente local também pode ser gerenciado pelo Redux. Você pode criar uma loja diretamente no seu construtor de componente. Este armazenamento local conteria o estado deste componente e trataria as ações relacionadas a este componente (e seus filhos passando a função dispatch deste armazenamento ou retornos de chamada que chamam essa função dispatch ) .

Esta arquitetura pode ser implementada manualmente, ou usar alguma biblioteca como redux-fractal, redux-ui e assim por diante.

Ou, como Dan apontou, você pode até implementar uma abordagem de estilo redutor para atualizar o estado de um componente também! Veja https://twitter.com/dan_abramov/status/736310245945933824

Eu quero saber onde armazenar o estado da IU, como indicador de atividade e abertura ou fechamento modal. O uso de setState causa problemas no teste de unidade dos componentes de reação?

@ akshay2604 : novamente, isso é com você. Veja os links que postei em comentários anteriores neste tópico. Você pode definitivamente usar setState ao testar componentes, especialmente se estiver usando a biblioteca Enzyme para ajudar a testá-los.

Deixe-me compartilhar meus pensamentos.

Eu categorizo ​​o estado em 3 categorias amplas de acordo com como ele está relacionado à entrada / saída do aplicativo:

  • "cache": um estado que é um espelho de dados persistentes. Exemplo:
{ "todos": [{ id: 1, title: "title" }, { id: 2, title: "title" }] }
  • "alterações": um estado que descreve alterações pendentes em dados persistentes. Exemplo:
{ "changeTodo": { title: "title", action: "add", done: false },
{ id: 1, title: "changed title", action: "modify", done: true }, { id: 2, action: "delete" } }
  • "visualização": um estado que transmite opções de visualização, como filtragem atual, classificação, etc. Exemplo:
{ "displayOptions": { searchTerm: "title", sort: ["title", "desc"], filter: "done=false" } }

Você não mistura cache com changes , você não mistura cache com view , você não mistura view com changes .

É claro que você precisa mesclá-los de alguma forma para exibi-los em um único componente de reação. Para que seu objeto "mesclado" se torne:

{ "todos": [{id: undefined, title: "title", done: false }, { id: 1, title: "changed title" }] }

Mas isso não é um estado, é o resultado da lógica do seu
Você pode armazenar em cache esse estado mesclado em seletores, pode armazená-lo na loja, pode armazená-lo em componentes, mas não é um "estado", não é importante, você pode facilmente reaplicar a função lógica do aplicativo a todas as 3 partes de estado e obter um estado mesclado novamente. É disso que trata a abordagem funcional.

Os mantenedores do Redux dirão "Ei, você deve implementar a lógica de sua aplicação como vários redutores e vários eventos, que irão construir diferentes partes de seu objeto" mesclado "."
Acho que é uma abordagem errada. Isso significa que você não conseguirá escapar do redux. O que deveria ser uma ferramenta para gerenciar seu estado, essencialmente se torna uma implementação da lógica de seu

Olá, estou pesquisando React / Redux por alguns dias, entendo a decisão tomada para escolher se algumas informações devem ser promovidas para armazenamento ou mantidas no estado local do componente.

Mas e se uma ação exigir os dois simultaneamente? Este é o caso de uso, que é muito comum:

  1. [contexto] A loja Redux é uma única folha { modelItems: myModelItems } . Ele armazena em cache (parte de / uma projeção de) o modelo de servidor
  2. [contexto] A visão é feita de um único componente inteligente MyItemsView que exibe uma lista de IU dos itens armazenados / em cache. Quando montado, o componente aciona uma busca de itens do modelo. Entrada de componente: myModelItems . Saída de componente: um gatilho de ação fetchModelItems . Componentes internos: state.busy e state.errorId
  3. [plano] Quando MyItemsView dispara fetchModelItems , uma solicitação HTTP é enviada ao servidor para buscar o modelo e armazená-lo em cache. Esta ação assíncrona tem 4 fases e tantos ganchos: onStarted (a solicitação HTTP está prestes a decolar, carregando o spinner começa no componente), onEnded (resposta HTTP pousada, carregando o spinner pára no componente , ainda não se olhou para o status da resposta), onFailed (uma notificação de erro é mostrada no componente) e onSucceed (o armazenamento Redux é atualizado e o cache de modelo que ele contém é encaminhado para o componente para renderização)

Portanto, como dividir o gatilho de ação fetchModelItems para que:

  • onStarted , onEnded e onFailed não foram para a loja Redux? Isso porque onStarted e onEnded são estados de IU temporários que não devem ter interação com o cache do modelo. O mesmo vale para onFailed (o cache do modelo permanece inalterado e a IU renderizará uma notificação de erro). MyItemsView renderizará o estado da IU aqui, não o modelo em cache
  • onSucceed chega à loja Redux? Isso porque ele ganhou na loteria de cache de modelos, tem acesso à fonte da verdade, tomará banho e hidratará novamente e, em seguida, renderizará myModelItems em MyItemsView

Sobre a implementação em minha tentativa atual, Redux Thunk cuida do gatilho de ação fetchModelItems . Eu sinto que escolhi o caminho Redux lá, e que não posso mais mudar de ideia para dizer "basta passar o sucesso assíncrono para a loja Redux, manter tudo o mais no estado do componente React".

Intrigado com isso, busco sucessos para armazenar, que encaminha para o componente conectado (ou seja, o contêiner Redux). Mas nenhum botão giratório de carregamento e um atm de mensagem de erro registrado no console miserável. Não quero definir store.ui.myItemsView.busy nem store.ui.myItemsView.errorId , mas apenas obter essas informações no estado do componente.

@pascalav :
Este é um rastreador de bug, não um sistema de suporte. Para questões de uso, use Stack Overflow ou Reactiflux onde há muito mais pessoas prontas para ajudá-lo - você provavelmente obterá uma resposta melhor mais rápido. Obrigado!

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

vslinko picture vslinko  ·  3Comentários

CellOcean picture CellOcean  ·  3Comentários

timdorr picture timdorr  ·  3Comentários

mickeyreiss-visor picture mickeyreiss-visor  ·  3Comentários

olalonde picture olalonde  ·  3Comentários