Dans le monde actuel des frameworks d'application Javascript, la philosophie de conception est le facteur clé de différenciation. Si vous comparez les frameworks JS populaires, tels que EmberJS, AngularJS, Backbone, Knockout, etc., vous êtes sûr de trouver des différences dans leurs abstractions, leurs modèles de pensée et, bien sûr, leur terminologie. Ceci est une conséquence directe de la philosophie de conception sous-jacente. Mais, en principe, ils font tous une chose, qui consiste à faire abstraction du DOM de manière à ne pas traiter directement avec les éléments HTML..
Je pense personnellement qu'un cadre devient intéressant lorsqu'il fournit un ensemble d'abstractions permettant un mode de pensée différent. Dans cet aspect, réagissez, le nouveau cadre JS des responsables de Facebook vous obligera à repenser (dans une certaine mesure) la façon dont vous décomposez l'interface utilisateur et les interactions de votre application. Ayant atteint la version 0.4.1 (à ce jour), React fournit un modèle à la fois simple et efficace pour créer des applications JS qui mélange un délicieux cocktail d’un genre différent..
Dans cet article, nous allons explorer les éléments constitutifs de React et adopter un style de pensée qui peut sembler contre-intuitif dès le départ. Mais, comme le dit la documentation de React: "Donnez-lui cinq minutes" et vous verrez ensuite comment cette approche deviendra plus naturelle..
L'histoire de React a commencé dans les confins de Facebook, où elle s'est brassée pendant un moment. Ayant atteint un état suffisamment stable, les développeurs ont décidé de l’ouvrir en source quelques mois auparavant. Fait intéressant, le site Web Instagram est également optimisé par le framework React.
React aborde le problème de l'abstraction DOM avec une approche légèrement différente. Pour comprendre en quoi cela est différent, passons rapidement en revue les techniques adoptées par les cadres que j'ai mentionnés plus tôt..
Le modèle de conception MVC (Model-View-Controller) est fondamental pour le développement d'interface utilisateur, non seulement dans les applications Web, mais également dans les applications frontales sur toutes les plateformes. Dans le cas d'applications Web, le DOM est la représentation physique d'une vue. Le DOM lui-même est généré à partir d'un modèle HTML textuel extrait d'un fichier différent, d'un bloc de script ou d'une fonction de modèle précompilée. le Vue
est une entité qui donne vie au modèle textuel en tant que fragment DOM. Il met également en place des gestionnaires d’événements et s’occupe de manipuler l’arbre DOM dans le cadre de son cycle de vie..
Pour le Vue
pour être utile, il doit afficher certaines données et éventuellement permettre l’interaction de l’utilisateur. Les données sont les Modèle
, qui provient d'une source de données (base de données, service Web, stockage local, etc.). Les cadres permettent de "lier" les données à la vue, de telle sorte que les modifications apportées aux données sont automatiquement répercutées avec les modifications apportées à la vue. Ce processus automatique s'appelle liaison de données et il y a des API / techniques pour rendre cela aussi transparent que possible.
La triade MVC est complétée par le Manette
, qui engage le Vue
et le Modèle
et orchestre le flux de données (Modèle
) dans le Vue
et des événements utilisateur sur le Vue
, conduisant éventuellement à des changements dans la Modèle
.
Les cadres qui gèrent automatiquement le flux de données entre la vue et le modèle conservent une boucle d'événement interne. Cette boucle d'événement est nécessaire pour écouter certains événements utilisateur, événements de modification de données, déclencheurs externes, etc., puis pour déterminer s'il y a eu des modifications par rapport à l'exécution précédente de la boucle. S'il y a des changements, à l'une ou l'autre extrémité (View ou Model), l'infrastructure veille à ce que les deux soient ramenés en synchronisation.
Avec React, la partie vue de la triade MVC prend de l’importance et est intégrée à une entité appelée Composant
. Le composant maintient un sac de propriété immuable appelé les accessoires
, et un Etat
cela représente l'état utilisateur de l'interface utilisateur. La partie génération de vues du Composant
est plutôt intéressant et peut-être la raison pour laquelle React se démarque des autres frameworks. Au lieu de construire un DOM physique directement à partir d’un fichier modèle / script / fonction, le Composant
génère un DOM intermédiaire qui remplace le réel DOM HTML. Une étape supplémentaire est ensuite prise pour traduire ce DOM intermédiaire dans le réel DOM HTML..
Dans le cadre de la génération de DOM intermédiaire, le Composant
attache également des gestionnaires d’événements et lie les données contenues dans les accessoires
et Etat
.
Si l'idée d'un DOM intermédiaire semble un peu étrange, ne vous inquiétez pas trop. Vous avez déjà vu cette stratégie adoptée par les runtimes de langage (ou machines virtuelles) pour les langages interprétés. Notre propre moteur d'exécution JavaScript génère d'abord une représentation intermédiaire avant de cracher le code natif. Ceci est également vrai pour d'autres langages basés sur des machines virtuelles tels que Java, C #, Ruby, Python, etc..
React adopte intelligemment cette stratégie pour créer un DOM intermédiaire avant de générer le DOM HTML final. Le DOM-intermédiaire est juste un graphe d'objet JavaScript et n'est pas rendu directement. Il y a une étape de traduction qui crée le vrai DOM. C’est la technique sous-jacente qui permet à React d’effectuer des manipulations rapides du DOM.
Pour avoir une meilleure idée de la façon dont React fait tout fonctionner, plongons un peu plus loin; en commençant par le Composant
. Le composant est le bloc de construction principal de React. Vous pouvez composer l'interface utilisateur de votre application en assemblant une arborescence de composants. Chaque composant fournit une implémentation pour le rendre()
méthode, où il crée le DOM intermédiaire. Appel React.renderComponent ()
Sur le composant racine, il en résulte une descente récursive de l'arborescence des composants et la construction du DOM intermédiaire. Le DOM intermédiaire est ensuite converti en réel DOM HTML..
Etant donné que la création de DOM intermédiaire fait partie intégrante du composant, React fournit une extension commode à JavaScript basée sur XML, appelée JSX, permettant de créer l’arborescence des composants sous la forme d’un ensemble de nœuds XML. Cela facilite la visualisation et le raisonnement sur le DOM. JSX simplifie également l'association des gestionnaires d'événements et des propriétés en tant qu'attributs xml. Comme JSX est un langage d'extension, il existe un outil (en ligne de commande et dans le navigateur) pour générer le code JavaScript final. Un nœud XML JSX mappe directement à un composant. Il convient de souligner que React fonctionne indépendamment de JSX et que le langage JSX ne permet que de créer facilement le DOM intermédiaire..
Le cadre de base de React peut être téléchargé à partir de leur site Web. En outre, pour la transformation JSX → JS, vous pouvez utiliser le fichier JSXTransformer intégré au navigateur ou utiliser l'outil de ligne de commande, appelé react-tools (installé via NPM). Vous aurez besoin d’une installation de Node.js pour le télécharger. L'outil de ligne de commande vous permet de précompiler les fichiers JSX et d'éviter la traduction dans le navigateur. Ceci est certainement recommandé si vos fichiers JSX sont volumineux ou nombreux..
Très bien, nous avons vu beaucoup de théorie jusqu’à présent, et je suis sûr que vous avez hâte de voir du vrai code. Passons à notre premier exemple:
/ ** @jsx React.DOM * / var Simple = React.createClass (getInitialState: function () return count: 0;, handleMouseDown: function () alert ('On m'a dit:' + ceci. props.message); this.setState (count: this.state.count + 1);, rendu: function () return; ); React.renderComponent (Donne moi le message!Message transmis this.state.count fois), document.body);
Bien que simple, le code ci-dessus couvre une bonne partie de la surface de React:
React.createClass
et en passant dans un objet qui implémente certaines fonctions essentielles. Le plus important est le rendre()
, qui génère le DOM intermédiaire.
La syntaxe est utile pour incorporer des expressions JavaScript pour les attributs (onMouseDown = this.handleClick
) et des nœuds enfants (this.state.count
). Les gestionnaires d'événements associés à l'aide de la syntaxe sont automatiquement liés à l'instance du composant. Ainsi ce
à l'intérieur de la fonction de gestionnaire d'événement fait référence à l'occurrence du composant. Le commentaire sur la première ligne / ** @jsx React.DOM * /
est un signal pour que le transformateur JSX fasse la traduction en JS. Sans cette ligne de commentaire, aucune traduction n'aura lieu. Nous pouvons exécuter l'outil de ligne de commande (jsx) en mode veille et compiler automatiquement les modifications de JSX → JS. Les fichiers source sont en / src dossier et la sortie est générée dans /construire.
jsx --watch src / build /
Voici le fichier JS généré:
/ ** @jsx React.DOM * / var Simple = React.createClass (displayName: 'Simple', getInitialState: function () return count: 0;, handleMouseDown: function () alert ('I was dit: '+ this.props.message); this.setState (count: this.state.count + 1);, rendre: function () return React.DOM.div (null, React.DOM.div. (className: "clicker", onMouseDown: this.handleMouseDown, "Give me the message!"), React.DOM.div (className: "message", "Message transmis", React.DOM.span ( className: "count", this.state.count), "time (s)"));); React.renderComponent (Simple (message: "Keep it Simple"), document.body);
Remarquez comment et
les étiquettes mappent vers des instances de
React.DOM.div
et React.DOM.span
.
handleMouseDown
, nous nous servons de this.props
lire le message propriété qui a été passé en. Nous avons mis la message sur la dernière ligne de l'extrait, dans l'appel à React.renderComponent ()
où nous créons le
composant. Le but de this.props
est de stocker les données qui ont été transmises au composant. Il est considéré comme immuable et seul un composant de niveau supérieur est autorisé à effectuer des modifications et à le transmettre à l'arborescence des composants..handleMouseDown
nous définissons également un état utilisateur avec this.setState ()
pour suivre le nombre d'affichages du message. Vous remarquerez que nous utilisons cet.etat
dans le rendre()
méthode. Chaque fois que vous appelez setState ()
, Réagir déclenche également la rendre()
méthode pour garder le DOM en synchronisation. outre React.renderComponent ()
, setState ()
est un autre moyen de forcer un rafraîchissement visuel.Les événements exposés sur le DOM intermédiaire, tels que le onMouseDown
, agissent également en tant que couche d'indirection avant qu'ils ne soient définis sur le real-DOM. Ces événements sont donc désignés sous le nom de Événements synthétiques. React adopte la délégation d'événements, qui est une technique bien connue, et attache les événements uniquement au niveau racine du real-DOM. Ainsi, il n'y a qu'un seul vrai gestionnaire d'événements sur le real-DOM. De plus, ces événements synthétiques offrent également un niveau de cohérence en masquant les différences entre les navigateurs et les éléments..
La combinaison des événements intermédiaires-DOM et synthétiques vous offre un moyen standard et cohérent de définir des interfaces utilisateur sur différents navigateurs et même périphériques..
Les composants du framework React ont un cycle de vie spécifique et incorporent une machine à états à trois états distincts..
La composante prend vie après avoir été Monté. Le montage entraîne le passage d'un render-pass générant l'arborescence des composants (intermédiaire-DOM). Cet arbre est converti et placé dans un noeud de conteneur du vrai DOM. C’est le résultat direct de l’appel à React.renderComponent ()
.
Une fois monté, le composant reste dans le Mettre à jour Etat. Un composant est mis à jour lorsque vous changez d'état à l'aide de setState ()
ou changer les accessoires en utilisant setProps ()
. Cela se traduit par un appel rendre()
, qui met le DOM en synchronisation avec les données (les accessoires
+ Etat
). Entre les mises à jour ultérieures, React calculera le delta entre l’arborescence des composants précédente et l’arborescence nouvellement générée. C'est une étape hautement optimisée (et une fonctionnalité phare) qui minimise la manipulation sur le vrai DOM.
L'état final est Non monté. Cela se produit lorsque vous appelez explicitement React.unmountAndReleaseReactRootNode ()
ou automatiquement si un composant était un enfant qui n'était plus généré dans un rendre()
appel. Le plus souvent, vous n'avez pas à vous en préoccuper et à laisser React faire le bon choix.
C’était bien grave, si React ne vous avait pas dit quand il se serait déplacé entre le Monté-mise à jour-non monté États. Heureusement, ce n'est pas le cas et vous pouvez remplacer certains crochets pour être averti des modifications apportées au cycle de vie. Les noms parlent d'eux-mêmes:
getInitialState ()
: prépare l'état initial du composantcomposantWillMount ()
composantDidMount ()
composantWillReceiveProps ()
shouldComponentUpdate ()
: utile si vous voulez contrôler quand un rendu doit être ignoré. composantWillUpdate ()
rendre()
composantDidUpdate ()
composantWillUnmount ()
le composantWill *
les méthodes sont appelées avant le changement d'état et la composantDid *
les méthodes sont appelées après.
Dans une arborescence de composants, les données doivent toujours être transmises vers le bas. Un composant parent doit définir la les accessoires
d'un composant enfant pour transmettre les données du parent à l'enfant. Ceci est appelé comme Propriétaire paire. Par ailleurs, les événements utilisateur (souris, clavier, touches) bouillonneront toujours de l’enfant jusqu’au composant racine, à moins qu’ils ne soient gérés entre.
Lorsque vous créez le DOM intermédiaire dans rendre()
, vous pouvez aussi assigner un ref
propriété à un composant enfant. Vous pouvez ensuite vous y référer depuis le parent en utilisant le refs
propriété. Ceci est décrit dans l'extrait ci-dessous.
render: function () // Définit un retour de référencethis.state.count; handleMouseDown: function () // Utilise la ref console.log (this.refs.counter.innerHTML); ,
Dans le cadre des métadonnées du composant, vous pouvez définir l’état initial (getInitialState ()
), que nous avons vu précédemment dans les méthodes du cycle de vie. Vous pouvez également définir les valeurs par défaut des accessoires avec getDefaultProps ()
et aussi établir des règles de validation sur ces accessoires en utilisant propTypes
. La documentation donne un bon aperçu des différents types de validations (vérifications de type, obligatoires, etc.) que vous pouvez effectuer..
React soutient également le concept de Mixin extraire des éléments de comportement réutilisables pouvant être injectés dans des composants disparates. Vous pouvez passer les mixins en utilisant le mixins
propriété d'un composant.
Maintenant, passons aux choses réelles et construisons un composant plus complet qui utilise ces fonctionnalités.
Dans cet exemple, nous allons construire un éditeur qui accepte un simple DSL (Domain Specific Language) pour créer des formes. Au fur et à mesure que vous tapez, vous verrez la sortie correspondante sur le côté, ce qui vous donnera des informations en direct.
Le DSL vous permet de créer trois types de formes: Ellipse, Rectangle et Texte. Chaque forme est spécifiée sur une ligne distincte avec un ensemble de propriétés de style. La syntaxe est simple et emprunte un peu à CSS. Pour analyser une ligne, nous utilisons un regex qui ressemble à ceci:
var shapeRegex = / (rect | ellipse | text) (\ s [a-z] +: \ s [a-z0-9] +;) * / i;
À titre d’exemple, l’ensemble de lignes suivant décrit deux rectangles et une étiquette de texte…
// valeur du texte de l'étiquette de réaction: React; couleur: # 00D8FF; taille de police: 48px; ombre du texte: 1px 1px 3px # 555; rembourrage: 10px; à gauche: 100px; en haut: 100px; // gauche logo rect fond: url (react.png) no-repeat; bordure: aucune; largeur: 38; hauteur: 38; à gauche: 60px; en haut: 120 px; // logo de fond droit: url (react.png) no-repeat; bordure: aucune; largeur: 38; hauteur: 38; à gauche: 250 pixels; en haut: 120 px;
… Générer la sortie indiquée ci-dessous:
Bon, allons de l'avant et construisons cet éditeur. Nous commencerons par le fichier HTML (index.html
), où nous mettons dans le balisage de niveau supérieur et incluons les bibliothèques et les scripts d’application. Je ne montre que les parties pertinentes ici:
Dans l'extrait ci-dessus, le récipient
div détient notre DOM généré par React. Nos scripts d’application sont inclus à partir du /construire
annuaire. Nous utilisons JSX dans nos composants et l’observateur de ligne de commande (jsx
), met les fichiers JS convertis en /construire
. Notez que cette commande watcher fait partie de la outils de réaction
Module NPM.
jsx --watch src / build /
L'éditeur est divisé en un ensemble de composants, énumérés ci-dessous:
mixins
propriété.La relation entre ces entités est montrée dans l'arborescence des composants annotée:
Regardons l’implémentation de certains de ces composants, en commençant par ShapeEditor.
/ ** @jsx React.DOM * / var ShapeEditor = React.createClass (composantWillMount: function () this._parser = new ShapeParser ();, getInitialState: function () return text: ",, render: function () var shape = this._parser.parse (this.state.text); var tree = () arbre de retour; , handleTextChange: function (event) this.setState (text: event.target.value);
Comme son nom l’indique, ShapeEditor fournit l’expérience d’édition en générant les et les commentaires en direct sur le
sur le changement
événement (les événements dans React sont toujours nommés avec la casse du chameau) sur le et à chaque changement, définit le
texte
propriété du composant Etat
. Comme mentionné précédemment, chaque fois que vous définissez l'état à l'aide de setState ()
, Le rendu est appelé automatiquement. Dans ce cas, le rendre()
du ShapeEditor s’appelle où nous analysons le texte de l’état et reconstruisons les formes. Notez que nous commençons avec un état initial de texte vide, qui est défini dans le getInitialState ()
crochet.
Pour analyser le texte en un ensemble de formes, nous utilisons une instance du ShapeParser
. J'ai laissé de côté les détails de l'analyseur pour que la discussion reste centrée sur React. L’instance d’analyseur est créée dans le composantWillMount ()
crochet. Ceci est appelé juste avant le montage du composant et constitue un bon emplacement pour effectuer toute initialisation avant le premier rendu..
Il est généralement recommandé d’acheminer tous vos traitements complexes par le biais du rendre()
méthode. Les gestionnaires d’événements viennent de définir l’état en rendre()
est la plaque tournante de toute votre logique de base.
le Editeur de forme
utilise cette idée pour analyser l'intérieur de son rendre()
et transmet les formes détectées en définissant la formes
propriété du ShapeCanvas
. C’est ainsi que les données circulent dans l’arborescence des composants, depuis le propriétaire (Editeur de forme
) au propriétaire (ShapeCanvas
).
Une dernière chose à noter ici est que nous avons le commentaire de première ligne pour indiquer JSX → JS translation.
Ensuite, nous passerons aux composants ShapeCanvas et Ellipse, Rectangle et Text..
p> Le ShapeCanvas
est plutôt simple avec sa responsabilité principale de générer les données respectives
,
et
composants des définitions de forme passées (this.props.shapes
). Pour chaque forme, nous passons dans les propriétés analysées avec l'expression d'attribut: propriétés = shape.properties
.
/ ** @jsx React.DOM * / var ShapeCanvas = React.createClass (getDefaultProps: function () return formes: [];, render: function () var self = ceci; var shapeTree =this.props.shapes.map (fonction (s) return self._createShape (s);); var noTree =Aucune forme trouvée; retourne this.props.shapes.length> 0? shapeTree: noTree; , _createShape: function (shape) retour this._shapeMap [shape.type] (shape); , _shapeMap: ellipse: fonction (forme) retour; , rect: fonction (forme) retour ; , texte: fonction (forme) retour ; );
Une chose différente ici est que notre arborescence de composants n'est pas statique, comme dans ShapeEditor. Au lieu de cela, il est généré dynamiquement en passant en boucle sur les formes passées. Nous montrons aussi le "Aucune forme trouvée"
message s'il n'y a rien à montrer.
Toutes les formes ont une structure similaire et ne diffèrent que par le style. Ils utilisent également le ShapePropertyMixin
gérer la génération de style.
Voici Ellipse:
/ ** @jsx React.DOM * / var Ellipse = React.createClass (mixins: [ShapePropertyMixin]], rendu: function () var style = this.extractStyle (true); style ['border-radius'] = ' 50% 50% '; retour ; );
La mise en œuvre pour extraitStyle ()
est fourni par le ShapePropertyMixin
.
Le composant Rectangle fait de même, bien entendu sans le rayon de la frontière style. Le composant Text a une propriété supplémentaire appelée valeur
qui définit le texte intérieur de la .
Voici le texte, pour que ce soit clair:
/ ** @jsx React.DOM * / var Text = React.createClass (mixins: [ShapePropertyMixin]], rendu: function () var style = this.extractStyle (false); retourthis.props.properties.value; );
app.js
est où nous réunissons tout cela. Ici, nous rendons le composant racine, le Editeur de forme
et également fournir un soutien pour basculer entre quelques formes d'échantillon. Lorsque vous sélectionnez un échantillon différent dans la liste déroulante, nous chargeons du texte prédéfini dans la Editeur de forme
et provoquer la ShapeCanvas
mettre à jour. Cela se passe dans le readShapes ()
méthode.
/ ** @jsx React.DOM * / var shapeEditor =; React.renderComponent (shapeEditor, document.getElementsByClassName ('conteneur') [0]); function readShapes () var fichier = $ ('. formes-sélecteur'). val (), texte = SHAPES [fichier] || "; $ ('. éditeur'). val (texte); shapeEditor.setState ( text: text); // force le rendu $ ('. Shapers-Picker'). Change (readShapes); readShapes (); // temps de chargement
Pour exercer le côté créatif, voici un robot construit à l'aide de l'éditeur de forme:
Phew! Cet article a été assez long et, une fois arrivé à ce point, vous devriez avoir un sentiment d'accomplissement!
Nous avons exploré beaucoup de concepts ici: le rôle intégral des composants dans le cadre, l’utilisation de JSX pour décrire facilement une arborescence de composants (aka intermédiaire-DOM), divers crochets à connecter au cycle de vie des composants, l’utilisation de Etat
et les accessoires
pour diriger le processus de rendu, utilisez Mixins pour intégrer le comportement réutilisable et, finalement, associez tout cela à l'exemple de Shape Editor..
J'espère que cet article vous donnera suffisamment de dynamisme pour vous permettre de créer quelques applications React. Pour continuer votre exploration, voici quelques liens utiles: