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
const Child = ({fromChildToParentCallback}) => (
<div onClick={() => fromChildToParentCallback(42)}>
Click me
</div>
);
class Parent extends React.Component {
receiveChildValue = (value) => {
console.log("Parent received value from child: " + value); // value is 42
};
render() {
return (
<Child fromChildToParentCallback={this.receiveChildValue}/>
)
}
}
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 que smart 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.
const AppContext = React.createContext(null)
class App extends React.Component {
render() {
return (
<AppContext.Provider value={{language: "en",userId: 42}}>
<div>
...
<SomeDeeplyNestedComponent/>
...
</div>
</AppContext.Provider>
)
}
};
const SomeDeeplyNestedComponent = () => (
<AppContext.Consumer>
{({language}) => <div>App language is currently {language}</div>}
</AppContext.Consumer>
);
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:
<div className="a">
a content
<Portal target="body">
<div className="b">
b content
</div>
</Portal>
</div>
Pode produzir o seguinte DOM quando renderizado dentro reactAppContainer
:
<body>
<div id="reactAppContainer">
<div className="a">
a content
</div>
</div>
<div className="b">
b content
</div>
</body>
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.
import { Slot, Fill } from 'react-slot-fill';
const Toolbar = (props) =>
<div>
<Slot name="ToolbarContent" />
</div>
export default Toolbar;
export const FillToolbar = ({children}) =>
<Fill name="ToolbarContent">
{children}
</Fill>
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 :
Para comunicação entre dois componentes que não têm um relacionamento pai-filho, é possível configurar seu próprio sistema de eventos global. Inscreva-se nos eventos em componentDidMount (), cancele a inscrição em componentWillUnmount () e chame setState () quando receber um evento.
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!