Acabei de começar o ReactJS e estou um pouco preso em um problema que tenho.
Minha aplicação é essencialmente uma lista com filtros e um botão para alterar o layout. No momento eu estou usando três componentes: <list />
, < Filters />
e <TopBar />
, agora, obviamente, quando eu alterar as configurações em < Filters />
que deseja acionar algum método em <list />
atualizar meu ponto de vista.
Como posso fazer com que esses três componentes interajam, ou preciso de algum tipo de modelo de dados global para o qual eu possa fazer alterações?
javascript
reactjs
woutr_be
fonte
fonte
Respostas:
A melhor abordagem dependeria de como você planeja organizar esses componentes. Alguns exemplos de cenários que vêm à mente agora:
<Filters />
é um componente filho de<List />
<Filters />
e<List />
são filhos de um componente pai<Filters />
e<List />
viva inteiramente em componentes raiz separados.Pode haver outros cenários em que não estou pensando. Se o seu não se encaixar nesses, informe-me. Aqui estão alguns exemplos aproximados de como eu lidei com os dois primeiros cenários:
Cenário 1
Você pode passar um manipulador de
<List />
para<Filters />
, que pode ser chamado noonChange
evento para filtrar a lista com o valor atual.JSFiddle para # 1 →
Cenário # 2
Semelhante ao cenário nº 1, mas será o componente pai que passa a função manipuladora
<Filters />
e passará a lista filtrada para<List />
. Eu gosto mais desse método, pois desacopla o<List />
do<Filters />
.JSFiddle para # 2 →
Cenário # 3
Quando os componentes não podem se comunicar entre nenhum tipo de relacionamento pai-filho, a documentação recomenda a configuração de um sistema global de eventos .
fonte
updateFilter
a<Filters />
e uma matriz comoitems
a<List />
. Você pode usar esses componentes filhos em outros pais com comportamentos diferentes, juntos ou sozinhos. Por exemplo, se você queria exibir uma lista dinâmica, mas não precisava de filtragem.Existem várias maneiras de fazer com que os componentes se comuniquem. Alguns podem ser adequados ao seu caso de usuário. Aqui está uma lista de alguns que eu achei úteis.
Reagir
Comunicação direta entre pais e filhos
Aqui, o componente filho chamará um retorno de chamada fornecido pelo pai com um valor, e o pai poderá obter o valor fornecido pelos filhos no pai.
Se você criar um recurso / página do seu aplicativo, é melhor ter um pai solteiro gerenciando os retornos de chamada / estado (também chamado de )
container
ou quesmart component
todos os filhos sejam apátridas, relatando apenas as coisas ao pai. Dessa forma, você pode "compartilhar" facilmente o estado dos pais com qualquer criança que precise dele.Contexto
O React Context permite manter o estado na raiz da hierarquia de componentes e ser capaz de injetar esse estado facilmente em componentes muito profundamente aninhados, sem a necessidade de passar adereços para todos os componentes intermediários.
Até agora, o contexto era um recurso experimental, mas uma nova API está disponível no React 16.3.
O consumidor está usando o padrão de função prop prop / children
Confira esta postagem no blog para obter mais detalhes.
Antes do React 16.3, eu recomendaria usar o react-broadcast, que oferece API bastante semelhante, e usar a API de contexto anterior.
Portais
Use um portal quando desejar manter 2 componentes próximos para fazê-los se comunicar com funções simples, como no pai / filho normal, mas você não deseja que esses 2 componentes tenham um relacionamento pai / filho no DOM, porque das restrições visuais / CSS que isso implica (como z-index, opacidade ...).
Nesse caso, você pode usar um "portal". Existem diferentes bibliotecas de reação usando portais , geralmente usados para modais , pop-ups, dicas de ferramentas ...
Considere o seguinte:
Pode produzir o seguinte DOM quando renderizado dentro
reactAppContainer
:Mais detalhes aqui
Slots
Você define um slot em algum lugar e preenche o slot a partir de outro local da sua árvore de renderização.
Isso é um pouco semelhante aos portais, exceto que o conteúdo preenchido será renderizado em um slot que você definir, enquanto os portais geralmente renderizam um novo nó dom (geralmente filhos de document.body)
Verifique a biblioteca react-slot-fill
Barramento de evento
Conforme indicado na documentação do React :
Há muitas coisas que você pode usar para configurar um barramento de eventos. Você pode simplesmente criar uma matriz de ouvintes e, na publicação do evento, todos os ouvintes receberiam o evento. Ou você pode usar algo como EventEmitter ou PostalJs
Fluxo
O fluxo é basicamente um barramento de eventos, exceto que os receptores de eventos são lojas. É semelhante ao sistema de barramento de eventos básico, exceto que o estado é gerenciado fora do React
A implementação original do Flux parece uma tentativa de obter fontes de eventos de maneira hacky.
O Redux é para mim a implementação do Flux que é a mais próxima da fonte de eventos, beneficiando muitas vantagens da fonte de eventos, como a capacidade de viajar no tempo. Não está estritamente vinculado ao React e também pode ser usado com outras bibliotecas de visualizações funcionais.
O tutorial em vídeo Redux da Egghead é muito bom e explica como funciona internamente (é realmente simples).
Cursores
Os cursores são provenientes do ClojureScript / Om e são amplamente utilizados em projetos React. Eles permitem gerenciar o estado fora do React e permitem que vários componentes tenham acesso de leitura / gravação à mesma parte do estado, sem precisar saber nada sobre a árvore de componentes.
Existem muitas implementações, incluindo ImmutableJS , React-cursors e Omniscient
Edit 2016 : parece que as pessoas concordam que os cursores funcionam bem em aplicativos menores, mas não se adaptam bem a aplicativos complexos. O Om Next não possui mais cursores (enquanto o Om introduziu o conceito inicialmente)
Arquitetura do olmo
A arquitetura Elm é uma arquitetura proposta para ser usada pela linguagem Elm . Mesmo que o Elm não seja o ReactJS, a arquitetura do Elm também pode ser feita no React.
Dan Abramov, autor do Redux, fez uma implementação da arquitetura Elm usando o React.
O Redux e o Elm são realmente ótimos e tendem a fortalecer os conceitos de fornecimento de eventos no frontend, permitindo a depuração de viagens no tempo, desfazer / refazer, repetir ...
A principal diferença entre Redux e Elm é que Elm tende a ser muito mais rigoroso em relação à administração do estado. No Elm, você não pode ter o estado do componente local ou montar / desmontar ganchos e todas as alterações do DOM devem ser acionadas por alterações globais do estado. A arquitetura Elm propõe uma abordagem escalável que permite manipular TODO o estado dentro de um único objeto imutável, enquanto o Redux propõe uma abordagem que convida você a manipular a maior parte do estado em um único objeto imutável.
Embora o modelo conceitual do Elm seja muito elegante e a arquitetura permita escalar bem em aplicativos grandes, na prática pode ser difícil ou envolver mais clichês para realizar tarefas simples, como focar uma entrada após a montagem ou integrar-se a uma biblioteca existente com uma interface imperativa (ou seja, plug-in JQuery). Assunto relacionado .
Além disso, a arquitetura Elm envolve mais clichês de código. Não é tão detalhado ou complicado de escrever, mas acho que a arquitetura Elm é mais adequada para linguagens estaticamente tipadas.
FRP
Bibliotecas como RxJS, BaconJS ou Kefir podem ser usadas para produzir fluxos FRP para lidar com a comunicação entre componentes.
Você pode tentar, por exemplo, Rx-React
Eu acho que o uso dessas bibliotecas é bastante semelhante ao uso do que a linguagem ELM oferece com sinais .
A estrutura CycleJS não usa ReactJS, mas usa vdom . Ele compartilha muitas semelhanças com a arquitetura Elm (mas é mais fácil de usar na vida real porque permite ganchos vdom) e usa RxJs extensivamente em vez de funções, e pode ser uma boa fonte de inspiração se você quiser usar o FRP com Reagir. Os vídeos do CycleJs Egghead são bons para entender como ele funciona.
CSP
Atualmente, o CSP (Communication Sequential Processes) é popular (principalmente por causa de Go / goroutines e core.async / ClojureScript), mas você pode usá-los também em javascript com JS-CSP .
James Long fez um vídeo explicando como ele pode ser usado com o React.
Sagas
Uma saga é um conceito de back-end que vem do mundo DDD / EventSourcing / CQRS, também chamado de "gerenciador de processos". Ele está sendo popularizado pelo projeto redux-saga , principalmente como um substituto ao redux-thunk para lidar com efeitos colaterais (por exemplo, chamadas de API etc.). Atualmente, a maioria das pessoas pensa que isso serve apenas para efeitos colaterais, mas na verdade é mais sobre dissociação de componentes.
É mais um elogio a uma arquitetura Flux (ou Redux) do que a um sistema de comunicação totalmente novo, porque a saga emite ações de Flux no final. A ideia é que, se você tiver o widget1 e o widget2 e desejar que eles sejam dissociados, não poderá disparar o widget2 de direcionamento de ação do widget1. Portanto, você faz apenas o widget1 disparar ações direcionadas a si mesmas, e a saga é um "processo em segundo plano" que escuta as ações do widget1 e pode despachar ações direcionadas ao widget2. A saga é o ponto de acoplamento entre os 2 widgets, mas os widgets permanecem desacoplados.
Se você estiver interessado, dê uma olhada na minha resposta aqui
Conclusão
Se você quiser ver um exemplo do mesmo pequeno aplicativo usando esses estilos diferentes, verifique as ramificações deste repositório .
Não sei qual é a melhor opção a longo prazo, mas realmente gosto da aparência do Flux como fonte de eventos.
Se você não conhece os conceitos de fornecimento de eventos, dê uma olhada neste blog muito pedagógico: Revolvendo o banco de dados com o apache Samza , é uma leitura obrigatória para entender por que o Flux é bom (mas isso também se aplica ao FRP) )
Acho que a comunidade concorda que a implementação mais promissora do Flux é o Redux , que permitirá progressivamente uma experiência produtiva do desenvolvedor, graças ao recarregamento a quente. A codificação ao vivo impressionante, ao lado de O vídeo Inventando sobre os Princípios de Bret Victor, é possível!
fonte
OK, existem poucas maneiras de fazer isso, mas eu quero exclusivamente focar no uso da loja usando o Redux, o que facilita muito a sua vida para essas situações, em vez de fornecer uma solução rápida apenas para esse caso, o uso do React puro vai acabar estragando tudo. aplicação real grande e comunicação entre componentes se torna cada vez mais difícil à medida que a aplicação cresce ...
Então, o que Redux faz por você?
O Redux é como o armazenamento local no seu aplicativo, que pode ser usado sempre que você precisar que os dados sejam usados em diferentes locais do seu aplicativo ...
Basicamente, a ideia do Redux vem originalmente do fluxo, mas com algumas mudanças fundamentais, incluindo o conceito de ter uma fonte de verdade criando apenas uma loja ...
Veja o gráfico abaixo para ver algumas diferenças entre o Flux e o Redux ...
Considere aplicar o Redux no seu aplicativo desde o início, se ele precisar de comunicação entre os Componentes ...
Também a leitura destas palavras da Redux Documentation pode ser útil para começar:
fonte
datepicker
(como um componente) e esse componente puder ser carregado de vários componentes que vivem na mesma página, como odatepicker
componente saberia qual ação enviar para redux? Essa é a essência do problema, vinculando uma ação em um componente a outro e NÃO a qualquer outro componente . (levar em consideração adatepicker
si é um componente muito, muito profunda dentro do próprio componente modal)redux
que você pode armazenar, mas como passar a ação profundamente para o que precisa ser acionado. Como um componente profundo sabe o que EXATAMENTE precisa ser acionado? Como no exemplo, forneci um componente geral que deve ser acionado para um redutor específico, dependendo do cenário, para que possa ser um redutor diferente, pois um modal de datapicker pode ser usado para qualquer componente.Foi assim que lidei com isso.
Digamos que você tenha uma <seleção> para o mês e uma <seleção> para o dia . O número de dias depende do mês selecionado.
Ambas as listas pertencem a um terceiro objeto, o painel esquerdo. Ambos <select> também são filhos do leftPanel <div>
É um jogo com retornos de chamada e manipuladores no componente LeftPanel .
Para testá-lo, basta copiar o código em dois arquivos separados e executar o index.html . Em seguida, selecione um mês e veja como o número de dias muda.
datas.js
E o HTML para executar o componente esquerdo do painel index.html
fonte
Vi que a pergunta já foi respondida, mas se você quiser saber mais detalhes, há um total de três casos de comunicação entre componentes :
fonte
Estendendo a resposta de @MichaelLaCroix quando um cenário é que os componentes não podem se comunicar entre nenhum tipo de relacionamento pai-filho, a documentação recomenda a configuração de um sistema de eventos global.
No caso de
<Filters />
e<TopBar />
não possui nenhuma das relações acima, um emissor global simples pode ser usado assim:componentDidMount
- Inscrever-se no eventocomponentWillUnmount
- Cancelar inscrição do eventoCódigo React.js e EventSystem
EventSystem.js
NotificationComponent.js
fonte
Existe essa possibilidade, mesmo que eles não sejam um relacionamento pai - filho - e esse seja o fluxo. Existe uma implementação muito boa (para mim pessoalmente) para o chamado Alt.JS (com o Alt-Container).
Por exemplo, você pode ter a Barra Lateral que depende do que está definido nos Detalhes do componente. A Barra Lateral do Componente está conectada com SidebarActions e SidebarStore, enquanto Detalhes é DetailsActions e DetailsStore.
Você pode usar o AltContainer assim
O que manteria as lojas (bem, eu poderia usar "store" em vez de "stores" prop). Agora, {this.props.content} PODE SER Detalhes dependendo da rota. Digamos que / Detalhes nos redirecionam para essa visualização. Os detalhes teriam, por exemplo, uma caixa de seleção que alteraria o elemento da Barra Lateral de X para Y se fosse marcado.
Tecnicamente, não há relação entre eles e seria difícil prescindir do fluxo. Mas com isso é bastante fácil.
Agora vamos para DetailsActions. Vamos criar lá
e DetailsStore
E agora, este é o lugar onde a mágica começa.
Como você pode ver, existe bindListener em SidebarActions.ComponentStatusChanged que será usado SE setSiteComponent será usado.
agora em SidebarActions
Nós temos tal coisa. Ele enviará esse objeto de plantão. E será chamado se setSiteComponent in store for usado (que você pode usar no componente, por exemplo, durante onChange no botão ot o que for)
Agora, na SidebarStore, teremos
Agora, aqui você pode ver que ele aguardará a DetailsStore. O que isso significa? mais ou menos, significa que esse método precisa aguardar a atualização DetailsStor para que ele possa se atualizar.
O One Store está ouvindo os métodos em uma loja e acionará uma ação da ação do componente, que atualizará sua própria loja.
Espero que possa ajudá-lo de alguma forma.
fonte
Se você quiser explorar as opções de comunicação entre componentes e sentir que está ficando cada vez mais difícil, considere adotar um bom padrão de design: Flux .
É simplesmente uma coleção de regras que define como você armazena e altera o estado amplo do aplicativo e usa esse estado para renderizar componentes.
Existem muitas implementações do Flux, e a implementação oficial do Facebook é uma delas. Embora seja considerado aquele que contém a maioria dos códigos padrão, mas é mais fácil entender, pois a maioria das coisas é explícita.
Alguns Outras alternativas são flummox fluxxor fluxible e redux .
fonte
Uma vez eu estava onde você está agora, como iniciante às vezes se sente deslocado sobre a maneira como reage a isso. Vou tentar abordar da mesma maneira que penso nisso agora.
Estados são a pedra angular da comunicação
Geralmente, o que se resume é a maneira como você altera os estados nesse componente. No seu caso, você aponta três componentes.
<List />
: Que provavelmente exibirá uma lista de itens, dependendo de um filtro<Filters />
: Opções de filtro que alterarão seus dados.<TopBar />
: Lista de opções.Para orquestrar toda essa interação, você precisará de um componente superior, vamos chamá-lo de App, que transmitirá ações e dados para cada um desses componentes, para que, por exemplo, possa ser assim
Portanto, quando
setFilter
é chamado, ele afetará o filterItem e renderizará novamente o componente ;. Caso isso não esteja totalmente claro, fiz um exemplo com a caixa de seleção que você pode verificar em um único arquivo:fonte
O código a seguir me ajuda a configurar a comunicação entre dois irmãos. A configuração é feita em seus pais durante as chamadas render () e componentDidMount (). É baseado em https://reactjs.org/docs/refs-and-the-dom.html Espero que ajude.
fonte
Estranhamente, ninguém mencionou
mobx
. A ideia é semelhante aredux
. Se eu tiver um dado em que vários componentes estão inscritos, eu posso usar esses dados para direcionar vários componentes.fonte