Sou novo no React / Redux. Eu uso um middleware fetch api no aplicativo Redux para processar as APIs. É ( redux-api-middleware ). Acho que é uma boa maneira de processar ações de API assíncronas. Mas encontro alguns casos que não podem ser resolvidos sozinho.
Como diz a página inicial ( Ciclo de Vida ), um ciclo de vida da API de busca começa com o despacho de uma ação CALL_API e termina com o despacho de uma ação FSA.
Portanto, meu primeiro caso é mostrar / ocultar um pré-carregador ao buscar APIs. O middleware despachará uma ação FSA no início e despachará uma ação FSA no final. Ambas as ações são recebidas por redutores que deveriam estar realizando apenas algum processamento normal de dados. Sem operações de interface do usuário, sem mais operações. Talvez eu deva salvar o status de processamento no estado e renderizá-los ao atualizar a loja.
Mas como fazer isso? Um fluxo de componente de reação em toda a página? o que acontece com a atualização da loja de outras ações? Quero dizer, eles são mais como eventos do que estado!
Pior ainda, o que devo fazer quando tiver que usar a caixa de diálogo de confirmação nativa ou a caixa de diálogo de alerta em aplicativos redux / react? Onde eles devem ser colocados, ações ou redutores?
Muitas felicidades! Desejo uma resposta.
fonte
Respostas:
Eu não diria isso. Eu acho que os indicadores de carregamento são um ótimo caso de IU que é facilmente descrito como uma função de estado: neste caso, de uma variável booleana. Embora essa resposta esteja correta, gostaria de fornecer um código para acompanhá-la.
No
async
exemplo do repo Redux , o redutor atualiza um campo chamadoisFetching
:O componente usa
connect()
do React Redux para assinar o estado da loja e retornaisFetching
como parte domapStateToProps()
valor de retorno para que esteja disponível nos props do componente conectado:Finalmente, o componente usa
isFetching
prop narender()
função para renderizar um rótulo “Carregando ...” (que poderia ser um spinner):Quaisquer efeitos colaterais (e mostrar uma caixa de diálogo é certamente um efeito colateral) não pertencem aos redutores. Pense nos redutores como “construtores de estado” passivos. Eles realmente não “fazem” coisas.
Se você deseja mostrar um alerta, faça isso de um componente antes de despachar uma ação ou faça isso de um criador de ação. No momento em que uma ação é despachada, é tarde demais para realizar os efeitos colaterais em resposta a ela.
Para cada regra, existe uma exceção. Às vezes, a lógica de seus efeitos colaterais é tão complicada que você realmente deseja acoplá-los a tipos de ação específicos ou a redutores específicos. Nesse caso, confira projetos avançados como Redux Saga e Redux Loop . Só faça isso quando você se sentir confortável com o Redux vanilla e tiver um problema real de efeitos colaterais dispersos que gostaria de tornar mais administrável.
fonte
Promise.all
em uma única promessa e então despachar uma única ação para todas as buscas. Ou você tem que manter váriasisFetching
variáveis em seu estado.isFetching
bandeira. Ele é definido para cada conjunto de objetos que estão sendo buscados. Você pode usar a composição do redutor para implementar isso.RECEIVE_POSTS
nunca for disparada, o sinal de carregamento permanecerá no local, a menos que você tenha criado algum tipo de tempo limite para mostrar umaerror loading
mensagem.Ótima resposta Dan Abramov! Só quero acrescentar que estava fazendo mais ou menos exatamente isso em um dos meus aplicativos (mantendo isFetching como um booleano) e acabei tendo que torná-lo um inteiro (que acaba sendo lido como o número de solicitações pendentes) para suportar vários pedidos simultâneos solicitações de.
com booleano:
solicitação 1 inicia -> girador ligado -> solicitação 2 inicia -> solicitação 1 termina -> spinner desligado -> solicitação 2 termina
com inteiro:
solicitação 1 inicia -> spinner ligado -> solicitação 2 inicia -> solicitação 1 termina -> solicitação 2 termina -> spinner desligado
fonte
isFetching
bandeira. Se você olhar atentamente para o exemplo que vinculei, verá que não há um objeto com,isFetched
mas muitos: um por subreddit (que é o que está sendo buscado naquele exemplo).fetchCounter
por alguma barra de progresso no topo da tela e várias específicasisFetching
bandeiras para listas e páginas.Eu gostaria de acrescentar algo. O exemplo do mundo real usa um campo
isFetching
na loja para representar quando uma coleção de itens está sendo buscada. Qualquer coleção é generalizada para umpagination
redutor que pode ser conectado aos seus componentes para rastrear o estado e mostrar se uma coleção está carregando.Aconteceu comigo que eu queria buscar detalhes para uma entidade específica que não se encaixa no padrão de paginação. Eu queria ter um estado representando se os detalhes estão sendo buscados no servidor, mas também não queria ter um redutor apenas para isso.
Para resolver isso, adicionei outro redutor genérico chamado
fetching
. Funciona de forma semelhante ao redutor de paginação e sua responsabilidade é apenas observar um conjunto de ações e gerar um novo estado com pares[entity, isFetching]
. Isso permite aoconnect
redutor de qualquer componente saber se o aplicativo está buscando dados não apenas para uma coleção, mas para uma entidade específica.fonte
Não me deparei com essa pergunta até agora, mas como nenhuma resposta é aceita, vou jogar meu chapéu. Eu escrevi uma ferramenta exatamente para este trabalho: react-loader-factory . É um pouco mais ativo do que a solução de Abramov, mas é mais modular e conveniente, já que não queria ter que pensar depois de escrevê-lo.
Existem quatro grandes peças:
const loaderWrapper = loaderFactory(actionsList, monitoredStates);
connect()
retorna no Redux), de modo que você pode apenas parafusá-lo em seu material existente.const LoadingChild = loaderWrapper(ChildComponent);
ACTION_SUCCESS
eACTION_REQUEST
, por exemplo). (Você pode enviar ações para outro lugar e apenas monitorar a partir do invólucro se quiser, é claro).O módulo em si é independente do redux-api-middleware, mas é com isso que eu o utilizo, então aqui está um exemplo de código do README:
Um componente com um carregador envolvendo-o:
Um redutor para o carregador monitorar (embora você possa conectá-lo de forma diferente, se desejar):
Espero que em um futuro próximo adicionarei coisas como tempo limite e erro ao módulo, mas o padrão não será muito diferente.
A resposta curta à sua pergunta é:
fonte
Sou o único a pensar que os indicadores de carregamento não pertencem a uma loja Redux? Quer dizer, não acho que seja parte do estado de um aplicativo em si.
Agora, eu trabalho com Angular2, e o que eu faço é que eu tenho um serviço de "carregamento" que expõe diferentes indicadores de carregamento via RxJS BehaviourSubjects .. Eu acho que o mecanismo é o mesmo, eu só não armazeno a informação no Redux.
Os usuários do LoadingService apenas se inscrevem nos eventos que desejam ouvir.
Meus criadores de ação Redux chamam o LoadingService sempre que algo precisa mudar. Os componentes UX assinam os observáveis expostos ...
fonte
Você pode adicionar ouvintes de alterações às suas lojas, usando o
connect()
React Redux ou ostore.subscribe()
método de baixo nível . Você deve ter o indicador de carregamento em sua loja, que o manipulador de alterações da loja pode verificar e atualizar o estado do componente. O componente então renderiza o pré-carregador, se necessário, com base no estado.alert
econfirm
não deve ser um problema. Eles estão bloqueando e o alerta nem mesmo aceita nenhuma entrada do usuário. Comconfirm
, você pode definir o estado com base no que o usuário clicou se a escolha do usuário afetar a renderização do componente. Caso contrário, você pode armazenar a escolha como variável de membro do componente para uso posterior.fonte
addNofication(message)
. Outro caso são os pré-carregadores que também são fornecidos pelo aplicativo nativo do host e acionados por sua API javascript. Eu adiciono um invólucro para essas APIs emcomponentDidUpdate
um componente React. Como faço para projetar os adereços ou o estado desse componente?Temos três tipos de notificações em nosso aplicativo, todos concebidos como aspectos:
Todos os três estão no nível superior de nosso aplicativo (Principal) e conectados por meio do Redux, conforme mostrado no trecho de código abaixo. Esses adereços controlam a exibição de seus aspectos correspondentes.
Projetei um proxy que lida com todas as nossas chamadas de API, portanto, todos os erros isFetching e (api) são mediados com actionCreators que eu importo no proxy. (Como um aparte, eu também uso o webpack para injetar uma simulação do serviço de apoio para dev para que possamos trabalhar sem dependências do servidor.)
Qualquer outro local no aplicativo que precise fornecer qualquer tipo de notificação simplesmente importa a ação apropriada. Snackbar & Error têm parâmetros para que as mensagens sejam exibidas.
) exportar a classe padrão Main extends React.Component {
fonte
Estou salvando os urls como ::
E então eu tenho um seletor memorizado (via nova seleção).
Para tornar o url único no caso de POST, passo alguma variável como consulta.
E onde quero mostrar um indicador, simplesmente uso a variável getFetchCount
fonte
Object.keys(items).filter(item => items[item] === true).length > 0 ? true : false
porObject.keys(items).every(item => items[item])
pelo caminho.some
vez deevery
, mas sim, muitas comparações desnecessárias na primeira solução proposta.Object.entries(items).some(([url, fetching]) => fetching);