Il existe plusieurs façons de faire communiquer les composants. Certains peuvent être adaptés à votre cas d'utilisation. Voici une liste de certains que j'ai trouvé utile de connaître.
Réagir
Communication directe parents / enfants
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}/>
)
}
}
Ici, le composant enfant appellera un rappel fourni par le parent avec une valeur, et le parent pourra obtenir la valeur fournie par les enfants du parent.
Si vous créez une fonctionnalité / page de votre application, il est préférable qu'un seul parent gère les rappels / l'état (également appelé container
ou smart component
) et que tous les enfants soient apatrides, ne signalant que les choses au parent. De cette façon, vous pouvez facilement «partager» l'état du parent à tout enfant qui en a besoin.
Le contexte
React Context permet de maintenir l'état à la racine de la hiérarchie de vos composants et de pouvoir injecter facilement cet état dans des composants imbriqués très profondément, sans avoir à passer des accessoires à tous les composants intermédiaires.
Jusqu'à présent, le contexte était une fonctionnalité expérimentale, mais une nouvelle API est disponible dans 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>
);
Le consommateur utilise le modèle de fonction render prop / children
Consultez cet article de blog pour plus de détails.
Avant React 16.3, je recommanderais d'utiliser react-broadcast qui offre une API assez similaire et d'utiliser l'ancienne API de contexte.
Portails
Utilisez un portail lorsque vous souhaitez garder 2 composants proches l'un de l'autre pour les faire communiquer avec des fonctions simples, comme dans un parent / enfant normal, mais vous ne voulez pas que ces 2 composants aient une relation parent / enfant dans le DOM, car des contraintes visuelles / CSS qu'elle implique (comme le z-index, l'opacité ...).
Dans ce cas, vous pouvez utiliser un "portail". Il existe différentes bibliothèques React utilisant des portails , généralement utilisés pour les modaux , les popups, les info-bulles ...
Considérer ce qui suit:
<div className="a">
a content
<Portal target="body">
<div className="b">
b content
</div>
</Portal>
</div>
Pourrait produire le DOM suivant lors du rendu à l'intérieur reactAppContainer
:
<body>
<div id="reactAppContainer">
<div className="a">
a content
</div>
</div>
<div className="b">
b content
</div>
</body>
Plus de détails ici
Machines à sous
Vous définissez un emplacement quelque part, puis vous remplissez l'emplacement à partir d'un autre endroit de votre arborescence de rendu.
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>
C'est un peu similaire aux portails, sauf que le contenu rempli sera rendu dans un emplacement que vous définissez, tandis que les portails rendent généralement un nouveau nœud dom (souvent un enfant de document.body)
Vérifier la bibliothèque React-Slot-Fill
Bus d'événement
Comme indiqué dans la documentation React :
Pour la communication entre deux composants qui n'ont pas de relation parent-enfant, vous pouvez configurer votre propre système d'événements global. Abonnez-vous aux événements dans componentDidMount (), désabonnez-vous dans componentWillUnmount () et appelez setState () lorsque vous recevez un événement.
Il existe de nombreuses choses que vous pouvez utiliser pour configurer un bus d'événements. Vous pouvez simplement créer un tableau d'auditeurs, et lors de la publication de l'événement, tous les écouteurs recevraient l'événement. Ou vous pouvez utiliser quelque chose comme EventEmitter ou PostalJs
Flux
Flux est essentiellement un bus d'événements, sauf que les récepteurs d'événements sont des magasins. Ceci est similaire au système de bus d'événements de base, sauf que l'état est géré en dehors de React
L'implémentation de Flux d'origine ressemble à une tentative de faire du sourcing d'événements de manière hacky.
Redux est pour moi l'implémentation de Flux qui est la plus proche de l'événementiel, et bénéficie de nombreux avantages de l'événementiel comme la possibilité de voyager dans le temps. Il n'est pas strictement lié à React et peut également être utilisé avec d'autres bibliothèques de vues fonctionnelles.
Le tutoriel vidéo Redux d'Egghead est vraiment sympa et explique comment cela fonctionne en interne (c'est vraiment simple).
Curseurs
Les curseurs proviennent de ClojureScript / Om et sont largement utilisés dans les projets React. Ils permettent de gérer l'état en dehors de React et permettent à plusieurs composants d'accéder en lecture / écriture à la même partie de l'état, sans avoir besoin de connaître quoi que ce soit sur l'arborescence des composants.
De nombreuses implémentations existent, y compris ImmutableJS , React-cursors et Omniscient
Edit 2016 : il semble que les gens conviennent que les curseurs fonctionnent bien pour les petites applications, mais il ne s'adapte pas bien aux applications complexes. Om Next n'a plus de curseurs (alors que c'est Om qui a introduit le concept initialement)
Architecture d'orme
L' architecture Elm est une architecture proposée pour être utilisée par le langage Elm . Même si Elm n'est pas ReactJS, l'architecture Elm peut également être réalisée dans React.
Dan Abramov, l'auteur de Redux, a réalisé une implémentation de l'architecture Elm en utilisant React.
Redux et Elm sont vraiment excellents et ont tendance à renforcer les concepts de sourcing d'événements sur le frontend, permettant à la fois le débogage dans le temps, l'annulation / la restauration, la relecture ...
La principale différence entre Redux et Elm est que Elm a tendance à être beaucoup plus strict sur la gestion de l'État. Dans Elm, vous ne pouvez pas avoir d'état de composant local ou de montage / démontage de crochets et toutes les modifications DOM doivent être déclenchées par des changements d'état globaux. L'architecture Elm propose une approche évolutive qui permet de gérer TOUS les états à l'intérieur d'un seul objet immuable, tandis que Redux propose une approche qui vous invite à gérer la PLUPART des états dans un seul objet immuable.
Alors que le modèle conceptuel d'Elm est très élégant et que l'architecture permet de bien évoluer sur de grandes applications, il peut en pratique être difficile ou impliquer plus de passe-partout pour réaliser des tâches simples comme donner le focus à une entrée après l'avoir montée, ou l'intégrer à une bibliothèque existante avec une interface impérative (ie plugin JQuery). Problème connexe .
De plus, l'architecture Elm implique davantage de code passe-partout. Ce n'est pas verbeux ou compliqué à écrire, mais je pense que l'architecture Elm est plus adaptée aux langages typés statiquement.
FRP
Des bibliothèques comme RxJS, BaconJS ou Kefir peuvent être utilisées pour produire des flux FRP pour gérer la communication entre les composants.
Vous pouvez essayer par exemple Rx-React
Je pense que l'utilisation de ces bibliothèques est assez similaire à l'utilisation de ce que le langage ELM offre avec des signaux .
Le framework CycleJS n'utilise pas ReactJS mais utilise vdom . Il partage beaucoup de similitudes avec l'architecture Elm (mais est plus facile à utiliser dans la vie réelle car il autorise les hooks vdom) et il utilise largement les RxJ au lieu des fonctions, et peut être une bonne source d'inspiration si vous souhaitez utiliser FRP avec Réagir. Les vidéos CycleJs Egghead sont agréables à comprendre comment cela fonctionne.
CSP
Les CSP (Communicating Sequential Processes) sont actuellement populaires (principalement à cause de Go / goroutines et core.async / ClojureScript) mais vous pouvez également les utiliser en javascript avec JS-CSP .
James Long a réalisé une vidéo expliquant comment il peut être utilisé avec React.
Sagas
Une saga est un concept de backend issu du monde DDD / EventSourcing / CQRS, également appelé "gestionnaire de processus". Il est popularisé par le projet redux-saga , principalement en remplacement de redux-thunk pour la gestion des effets secondaires (c'est-à-dire les appels API, etc.). La plupart des gens pensent actuellement qu'il ne sert que pour les effets secondaires, mais qu'il s'agit en fait davantage de découplage des composants.
C'est plus un complément à une architecture Flux (ou Redux) qu'un système de communication totalement nouveau, car la saga émet des actions Flux à la fin. L'idée est que si vous avez widget1 et widget2 et que vous souhaitez les découpler, vous ne pouvez pas déclencher d'action ciblant widget2 depuis widget1. Donc, vous ne faites que widget1 déclencher des actions qui se ciblent, et la saga est un "processus d'arrière-plan" qui écoute les actions widget1, et peut envoyer des actions qui ciblent widget2. La saga est le point de couplage entre les 2 widgets mais les widgets restent découplés.
Si vous êtes intéressé, regardez ma réponse ici
Conclusion
Si vous souhaitez voir un exemple de la même petite application utilisant ces différents styles, vérifiez les branches de ce référentiel .
Je ne sais pas quelle est la meilleure option à long terme mais j'aime vraiment à quoi Flux ressemble à un événementiel.
Si vous ne connaissez pas les concepts de l'événementiel, jetez un œil à ce blog très pédagogique: tourner la base de données à l'envers avec apache Samza , c'est une lecture incontournable pour comprendre pourquoi Flux est sympa (mais cela pourrait aussi s'appliquer à FRP )
Je pense que la communauté convient que l'implémentation la plus prometteuse de Flux est Redux , qui permettra progressivement une expérience de développeur très productive grâce au rechargement à chaud. Le livecoding impressionnant de la vidéo Inventing on Principle de Bret Victor est possible!