Estou criando um aplicativo que precisa mostrar uma caixa de diálogo de confirmação em algumas situações.
Digamos que eu queira remover algo, então enviarei uma ação como essa deleteSomething(id)
para que algum redutor pegue esse evento e preencha o redutor de diálogo para mostrá-lo.
Minha dúvida surge quando este diálogo é enviado.
- Como esse componente pode despachar a ação correta de acordo com a primeira ação despachada?
- O criador da ação deve lidar com essa lógica?
- Podemos adicionar ações dentro do redutor?
editar:
para deixar mais claro:
deleteThingA(id) => show dialog with Questions => deleteThingARemotely(id)
createThingB(id) => Show dialog with Questions => createThingBRemotely(id)
Então, eu estou tentando reutilizar o componente de diálogo. Mostrar / ocultar a caixa de diálogo não é o problema, pois isso pode ser feito facilmente no redutor. O que estou tentando especificar é como despachar a ação do lado direito, de acordo com a ação que inicia o fluxo no lado esquerdo.
javascript
modal-dialog
redux
react-redux
carlesba
fonte
fonte
Respostas:
A abordagem que sugiro é um pouco detalhada, mas achei que ela pode se adaptar muito bem a aplicativos complexos. Quando você quiser mostrar um modal, inicie uma ação descrevendo qual modal você gostaria de ver:
Despachando uma ação para mostrar o modal
(As strings podem ser constantes, é claro; estou usando strings inline para simplificar.)
Escrevendo um redutor para gerenciar o estado modal
Em seguida, verifique se você possui um redutor que aceite apenas esses valores:
Ótimo! Agora, quando você despacha uma ação,
state.modal
será atualizada para incluir as informações sobre a janela modal atualmente visível.Escrevendo o componente modal raiz
Na raiz da sua hierarquia de componentes, adicione um
<ModalRoot>
componente conectado ao repositório Redux. Ele escutarástate.modal
e exibirá um componente modal apropriado, encaminhando os adereços a partir dostate.modal.modalProps
.O que fizemos aqui?
ModalRoot
lê a correntemodalType
emodalProps
dastate.modal
qual está conectada e renderiza um componente correspondente, comoDeletePostModal
ouConfirmLogoutModal
. Todo modal é um componente!Escrevendo componentes modais específicos
Não há regras gerais aqui. Eles são apenas componentes do React que podem despachar ações, ler algo do estado da loja e são modais .
Por exemplo,
DeletePostModal
pode parecer com:O
DeletePostModal
está conectado à loja para exibir o título da postagem e funciona como qualquer componente conectado: pode despachar ações, incluindohideModal
quando é necessário se esconder.Extraindo um componente de apresentação
Seria estranho copiar e colar a mesma lógica de layout para cada modal "específico". Mas você tem componentes, certo? Então você pode extrair uma apresentação
<Modal>
componente de que não sabe o que modais específicos fazem, mas lida com a aparência deles.Em seguida, modais específicos, como
DeletePostModal
podem ser usados para renderização:Cabe a você criar um conjunto de adereços que
<Modal>
possam ser aceitos em seu aplicativo, mas eu imagino que você possa ter vários tipos de modais (por exemplo, informação modal, confirmação de confirmação etc.) e vários estilos para eles.Acessibilidade e ocultação ao clicar fora ou na tecla Escape
A última parte importante sobre os modais é que geralmente queremos ocultá-los quando o usuário clica fora ou pressiona Escape.
Em vez de dar conselhos sobre como implementar isso, sugiro que você não o implemente. É difícil acertar considerando a acessibilidade.
Em vez disso, sugiro que você use um componente modal acessível disponível no mercado, como
react-modal
. É completamente personalizável, você pode colocar o que quiser dentro dele, mas lida com a acessibilidade corretamente para que pessoas cegas ainda possam usar o seu modal.Você pode embrulhar
react-modal
você mesmo<Modal>
que aceita objetos específicos para seus aplicativos e gera botões filhos ou outro conteúdo. É tudo apenas componentes!Outras abordagens
Há mais de uma maneira de fazer isso.
Algumas pessoas não gostam da verbosidade dessa abordagem e preferem ter um
<Modal>
componente que possa renderizar diretamente dentro de seus componentes com uma técnica chamada "portais". Os portais permitem renderizar um componente dentro do seu enquanto na verdade ele será renderizado em um local predeterminado no DOM, o que é muito conveniente para os modais.De fato, ao qual
react-modal
eu vinculei anteriormente, já faz isso internamente, tecnicamente, você nem precisa renderizá-lo do topo. Ainda acho bom desacoplar o modal que quero mostrar do componente que o mostra, mas você também pode usarreact-modal
diretamente de seus componentes e pular a maior parte do que escrevi acima.Convido você a considerar as duas abordagens, experimentar com elas e escolher o que achar melhor para seu aplicativo e sua equipe.
fonte
modalProps
à ação. Isso viola a regra de manter o estado serializável. Como posso superar esse problema?Atualização : React 16.0 portais introduzidos através do
ReactDOM.createPortal
linkAtualização : as próximas versões do React (Fiber: provavelmente 16 ou 17) incluirão um método para criar portais:
ReactDOM.unstable_createPortal()
linkUse portais
Dan Abramov responder a primeira parte é bom, mas envolve muito clichê. Como ele disse, você também pode usar portais. Vou expandir um pouco essa ideia.
A vantagem de um portal é que o pop-up e o botão permaneçam muito próximos da árvore React, com uma comunicação pai / filho muito simples usando adereços: você pode lidar facilmente com ações assíncronas com portais ou permitir que o pai personalize o portal.
O que é um portal?
Um portal permite que você renderize diretamente dentro de
document.body
um elemento profundamente aninhado na sua árvore do React.A idéia é que, por exemplo, você renderize no corpo a seguinte árvore React:
E você obtém como saída:
O
inside-portal
nó foi traduzido para dentro<body>
, em vez de seu lugar normal e profundamente aninhado.Quando usar um portal
Um portal é particularmente útil para exibir elementos que devem estar no topo de seus componentes existentes do React: pop-ups, listas suspensas, sugestões, pontos de acesso
Por que usar um portal
Não há mais problemas com o índice z : um portal permite que você renderize
<body>
. Se você deseja exibir um pop-up ou uma lista suspensa, é uma ótima idéia se não quiser lutar contra problemas do índice z. Os elementos do portal são adicionadosdocument.body
em ordem de montagem, o que significa que, a menos que você brinquez-index
, o comportamento padrão será empilhar portais uns sobre os outros, em ordem de montagem. Na prática, isso significa que você pode abrir com segurança um pop-up de dentro de outro pop-up e certifique-se de que o segundo pop-up seja exibido na parte superior da primeira, sem ter que pensarz-index
.Na prática
Mais simples: use o estado local React: se você acha que, para um pop-up simples de confirmação de exclusão, não vale a pena ter o Redux, então você pode usar um portal e isso simplifica bastante o seu código. Para esse caso de uso, em que a interação é muito local e é realmente um detalhe de implementação, você realmente se preocupa com o carregamento quente, viagens no tempo, registro de ações e todos os benefícios que o Redux traz para você? Pessoalmente, eu não uso e estado local neste caso. O código se torna tão simples quanto:
Simples: você ainda pode usar o estado Redux : se realmente quiser, ainda pode
connect
escolher se deseja ou nãoDeleteConfirmationPopup
ser exibido. Como o portal permanece profundamente aninhado em sua árvore do React, é muito simples personalizar o comportamento desse portal, porque seu pai pode transmitir acessórios para o portal. Se você não usa portais, geralmente precisa exibir seus pop-ups no topo da árvore do React paraz-index
motivos e, geralmente, precisa pensar em coisas como "como personalizar o DeleteConfirmationPopup genérico que criei de acordo com o caso de uso " E geralmente você encontrará soluções bastante invasivas para esse problema, como despachar uma ação que contém ações de confirmação / cancelamento aninhadas, uma chave de pacote de conversão ou, pior ainda, uma função de renderização (ou outra coisa não serializável). Você não precisa fazer isso com portais e pode apenas passar adereços regulares, já queDeleteConfirmationPopup
é apenas um filho doDeleteButton
Conclusão
Portais são muito úteis para simplificar seu código. Eu não poderia mais ficar sem eles.
Observe que as implementações do portal também podem ajudá-lo com outros recursos úteis, como:
react-portal ou react-modal são ótimos para pop-ups, modais e sobreposições que devem ser em tela cheia, geralmente centralizadas no meio da tela.
O react-tether é desconhecido para a maioria dos desenvolvedores do React, mas é uma das ferramentas mais úteis que você pode encontrar por aí. O Tether permite criar portais, mas posicionará automaticamente o portal, em relação a um determinado destino. Isso é perfeito para dicas de ferramentas, listas suspensas, pontos ativos, caixas de ajuda ... Se você já teve algum problema com a posição
absolute
/relative
e /z-index
ou sua lista suspensa fora da janela de visualização, o Tether resolverá tudo isso para você.Você pode, por exemplo, implementar facilmente pontos de acesso integrados, que se expandem para uma dica de ferramenta uma vez clicados:
Código de produção real aqui. Não pode ser mais simples :)
Edit : recém-descoberto react-gateway que permite renderizar portais no nó de sua escolha (não necessariamente o corpo)
Edit : parece que o react-popper pode ser uma alternativa decente ao reat-tether. PopperJS é uma biblioteca que calcula apenas uma posição apropriada para um elemento, sem tocar diretamente no DOM, permitindo que o usuário escolha onde e quando deseja colocar o nó DOM, enquanto o Tether anexa diretamente ao corpo.
Edit : também há react-slot-fill, o que é interessante e pode ajudar a resolver problemas semelhantes, permitindo renderizar um elemento em um slot de elemento reservado que você coloca em qualquer lugar que desejar na sua árvore
fonte
<Portal>
vem? Acho que é o portal de reação, mas seria bom saber com certeza.Muitas soluções boas e comentários valiosos de especialistas conhecidos da comunidade JS sobre o tópico podem ser encontrados aqui. Pode ser um indicador de que não é esse problema trivial que possa parecer. Penso que é por isso que poderia ser a fonte de dúvidas e incertezas sobre o assunto.
O problema fundamental aqui é que no React você só pode montar o componente no pai, o que nem sempre é o comportamento desejado. Mas como resolver esse problema?
Proponho a solução, abordada para corrigir esse problema. Definição de problema mais detalhada, src e exemplos podem ser encontrados aqui: https://github.com/fckt/react-layer-stack#rationale
Dê uma olhada em https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example para ver o exemplo concreto que é a resposta à sua pergunta:
fonte
Na minha opinião, a implementação mínima básica tem dois requisitos. Um estado que controla se o modal está aberto ou não, e um portal para processar o modal fora da árvore de reação padrão.
O componente ModalContainer abaixo implementa esses requisitos, juntamente com as funções de renderização correspondentes para o modal e o acionador, responsáveis pela execução do retorno de chamada para abrir o modal.
E aqui está um caso de uso simples ...
Uso funções de renderização, porque quero isolar o gerenciamento de estado e a lógica do clichê da implementação do componente modal e do componente renderizado. Isso permite que os componentes renderizados sejam o que você deseja. No seu caso, suponho que o componente modal possa ser um componente conectado que recebe uma função de retorno de chamada que despacha uma ação assíncrona.
Se você precisar enviar adereços dinâmicos para o componente modal a partir do componente acionador, o que, esperamos, não aconteça com muita frequência, recomendo envolver o ModalContainer com um componente de contêiner que gerencia os adereços dinâmicos em seu próprio estado e aprimora os métodos de renderização originais, como tão.
fonte
Enrole o modal em um contêiner conectado e execute a operação assíncrona aqui. Dessa forma, você pode alcançar o envio para acionar ações e o suporte onClose também. Para chegar
dispatch
dos adereços, não passe amapDispatchToProps
função paraconnect
.O aplicativo em que o modal é renderizado e seu estado de visibilidade é definido:
fonte