Je viens du monde angulaire où je pourrais extraire la logique d'un service / usine et la consommer dans mes contrôleurs.
J'essaie de comprendre comment puis-je obtenir la même chose dans une application React.
Disons que j'ai un composant qui valide l'entrée du mot de passe de l'utilisateur (c'est la force). C'est la logique est assez complexe donc je ne veux pas l'écrire dans le composant lui-même.
Où dois-je écrire cette logique? Dans un magasin si j'utilise du flux? Ou y a-t-il une meilleure option?
reactjs
reactjs-flux
Dennis Nerush
la source
la source
Réponses:
La première réponse ne reflète pas le paradigme actuel Container vs Presenter .
Si vous avez besoin de faire quelque chose, comme valider un mot de passe, vous aurez probablement une fonction qui le fait. Vous passeriez cette fonction à votre vue réutilisable en tant qu'accessoire.
Conteneurs
Donc, la bonne façon de le faire est d'écrire un ValidatorContainer, qui aura cette fonction comme propriété, et d'y envelopper le formulaire, en passant les bons accessoires à l'enfant. En ce qui concerne votre vue, votre conteneur de validation encapsule votre vue et la vue utilise la logique des conteneurs.
La validation peut être entièrement effectuée dans les propriétés du conteneur, mais si vous utilisez un validateur tiers ou un service de validation simple, vous pouvez utiliser le service en tant que propriété du composant conteneur et l'utiliser dans les méthodes du conteneur. J'ai fait cela pour des composants reposants et cela fonctionne très bien.
Fournisseurs
S'il y a un peu plus de configuration nécessaire, vous pouvez utiliser un modèle fournisseur / consommateur. Un fournisseur est un composant de haut niveau qui s'enroule quelque part près de et sous l'objet d'application supérieur (celui que vous montez) et fournit une partie de lui-même, ou une propriété configurée dans la couche supérieure, à l'API de contexte. Je configure ensuite mes éléments de conteneur pour consommer le contexte.
Les relations de contexte parent / enfant n'ont pas besoin d'être proches les unes des autres, juste l'enfant doit être descendu d'une manière ou d'une autre. Redux stocke et le React Router fonctionne de cette manière. Je l'ai utilisé pour fournir un contexte reposant racine pour mes conteneurs de repos (si je ne fournis pas le mien).
(note: l'API context est marquée comme expérimentale dans la documentation, mais je ne pense pas que ce soit plus, compte tenu de ce qui l'utilise).
Intergiciel
Un autre moyen que je n'ai pas essayé, mais que j'ai vu utilisé, est d'utiliser un middleware en conjonction avec Redux. Vous définissez votre objet de service en dehors de l'application, ou au moins, plus haut que le magasin redux. Lors de la création du magasin, vous injectez le service dans le middleware et le middleware gère toutes les actions qui affectent le service.
De cette façon, je pourrais injecter mon objet restful.js dans le middleware et remplacer mes méthodes de conteneur par des actions indépendantes. J'aurais toujours besoin d'un composant de conteneur pour fournir les actions à la couche de vue de formulaire, mais connect () et mapDispatchToProps m'ont couvert.
Le nouveau react-router-redux v4 utilise cette méthode pour impacter l'état de l'historique, par exemple.
la source
Le problème devient extrêmement simple lorsque vous réalisez qu'un service Angular n'est qu'un objet qui fournit un ensemble de méthodes indépendantes du contexte. C'est juste le mécanisme Angular DI qui le rend plus compliqué. La DI est utile car elle s'occupe de créer et de maintenir des instances pour vous mais vous n'en avez pas vraiment besoin.
Considérez une bibliothèque AJAX populaire nommée axios (dont vous avez probablement entendu parler):
Cela ne se comporte-t-il pas comme un service? Il fournit un ensemble de méthodes responsables d'une logique spécifique et est indépendant du code principal.
Votre exemple de cas concernait la création d'un ensemble isolé de méthodes pour valider vos entrées (par exemple, vérifier la force du mot de passe). Certains ont suggéré de mettre ces méthodes à l'intérieur des composants, ce qui pour moi est clairement un anti-pattern. Que faire si la validation implique d'effectuer et de traiter des appels backend XHR ou de faire des calculs complexes? Mélangeriez-vous cette logique avec des gestionnaires de clics de souris et d'autres éléments spécifiques à l'interface utilisateur? Absurdité. La même chose avec l'approche conteneur / HOC. Emballer votre composant juste pour ajouter une méthode qui vérifiera si la valeur contient un chiffre? Allons.
Je voudrais simplement créer un nouveau fichier nommé `` ValidationService.js '' et l'organiser comme suit:
Puis dans votre composant:
Utilisez ce service où que vous soyez. Si les règles de validation changent, vous devez vous concentrer uniquement sur le fichier ValidationService.js.
Vous pourriez avoir besoin d'un service plus compliqué qui dépend d'autres services. Dans ce cas, votre fichier de service peut renvoyer un constructeur de classe au lieu d'un objet statique afin que vous puissiez créer vous-même une instance de l'objet dans le composant. Vous pouvez également envisager d'implémenter un singleton simple pour vous assurer qu'il n'y a toujours qu'une seule instance de l'objet de service en cours d'utilisation dans l'ensemble de l'application.
la source
J'avais besoin d'une logique de formatage à partager entre plusieurs composants et en tant que développeur Angular, je me suis naturellement tourné vers un service.
J'ai partagé la logique en la mettant dans un fichier séparé
puis l'a importé en tant que module
la source
Gardez à l'esprit que le but de React est de mieux coupler les choses qui devraient logiquement être couplées. Si vous concevez une méthode compliquée de «validation du mot de passe», où doit-elle être couplée?
Eh bien, vous allez devoir l'utiliser chaque fois que l'utilisateur doit saisir un nouveau mot de passe. Cela peut être sur l'écran d'enregistrement, un écran "mot de passe oublié", un écran "réinitialiser le mot de passe pour un autre utilisateur", etc.
Mais dans tous ces cas, il sera toujours lié à un champ de saisie de texte. C'est donc là que cela devrait être couplé.
Créez un très petit composant React composé uniquement d'un champ d'entrée et de la logique de validation associée. Entrez ce composant dans tous les formulaires qui pourraient souhaiter avoir une entrée de mot de passe.
C'est essentiellement le même résultat que d'avoir un service / une usine pour la logique, mais vous le couplez directement à l'entrée. Vous n'avez donc plus besoin de dire à cette fonction où chercher son entrée de validation, car elle est liée en permanence.
la source
Je viens également de la région Angular.js et les services et usines dans React.js sont plus simples.
Vous pouvez utiliser des fonctions ou des classes simples, un style de rappel et un événement Mobx comme moi :)
Voici un exemple simple:
la source
Même situation: Après avoir réalisé plusieurs projets Angular et être passé à React, ne pas avoir un moyen simple de fournir des services via DI semble être une pièce manquante (les détails du service mis à part).
En utilisant le contexte et les décorateurs ES7, nous pouvons nous en approcher:
https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/
Il semble que ces gars-là ont fait un pas de plus / dans une direction différente:
http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs
On a toujours envie de travailler à contre-courant. Revisitera cette réponse dans 6 mois après avoir entrepris un grand projet React.
EDIT: De retour 6 mois plus tard avec un peu plus d'expérience React. Considérez la nature de la logique:
Certains atteignent également des HOC pour la réutilisation, mais pour moi, ce qui précède couvre presque tous les cas d'utilisation. Envisagez également de mettre à l'échelle la gestion de l'état à l'aide de canards pour séparer les préoccupations et les états centrés sur l'interface utilisateur.
la source
Je viens également d'Angular et j'essaie React, à partir de maintenant, une méthode recommandée (?) Semble être d'utiliser des composants d'ordre élevé :
Disons que vous avez
input
ettextarea
aimez appliquer la même logique de validation:Ensuite, écrivez un HOC qui valide et stylise le composant enveloppé:
Désormais, ces HOC partagent le même comportement de validation:
J'ai créé une simple démo .
Edit : Une autre démonstration utilise des accessoires pour transmettre un tableau de fonctions afin que vous puissiez partager une logique composée de plusieurs fonctions de validation à travers des
HOC
s comme:Edit2 : React 16.8+ fournit une nouvelle fonctionnalité, Hook , une autre manière intéressante de partager la logique.
https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js
la source
HOC
, voir mon édition pour une autre démo.Le service n'est pas limité à Angular, même en Angular2 + ,
Le service est juste une collection de fonctions d'assistance ...
Et il existe de nombreuses façons de les créer et de les réutiliser dans l'application ...
1) Ils peuvent être toutes des fonctions séparées qui sont exportées à partir d'un fichier js, comme ci-dessous:
2) Nous pouvons également utiliser une méthode d'usine comme, avec collection de fonctions ... avec ES6, il peut s'agir d'une classe plutôt que d'un constructeur de fonction:
Dans ce cas, vous devez créer une instance avec une nouvelle clé ...
Dans ce cas également, chaque instance a sa propre vie, alors soyez prudent si vous souhaitez la partager, dans ce cas, vous ne devez exporter que l'instance que vous souhaitez ...
3) Si votre fonction et vos utils ne seront pas partagés, vous pouvez même les mettre dans le composant React, dans ce cas, tout comme la fonction dans votre composant react ...
4) Une autre façon de gérer les choses pourrait être d'utiliser Redux , c'est un magasin temporaire pour vous, donc si vous l'avez dans votre application React , cela peut vous aider avec de nombreuses fonctions de setter getter vous utilisez ... C'est comme un grand magasin qui gardent une trace de vos états et peuvent le partager entre vos composants, vous pouvez donc vous débarrasser de beaucoup de problèmes liés aux éléments de setter que nous utilisons dans les services ...
Il est toujours bon de faire un code DRY et de ne pas répéter ce qui doit être utilisé pour rendre le code réutilisable et lisible, mais n'essayez pas de suivre les méthodes angulaires dans l'application React , comme mentionné au point 4, l'utilisation de Redux peut réduire votre besoin de services et vous limitez leur utilisation pour certaines fonctions d'assistance réutilisables comme l'élément 1 ...
la source
Je suis dans la même botte que toi. Dans le cas que vous mentionnez, j'implémenterais le composant d'interface utilisateur de validation d'entrée en tant que composant React.
Je suis d'accord que la mise en œuvre de la logique de validation elle-même ne doit (doit) pas être couplée. Par conséquent, je le mettrais dans un module JS séparé.
Autrement dit, pour la logique qui ne doit pas être couplée, utilisez un module / une classe JS dans un fichier séparé et utilisez require / import pour dissocier le composant du "service".
Cela permet l'injection de dépendances et le test unitaire des deux indépendamment.
la source
ou vous pouvez injecter l'héritage de classe "http" dans React Component
via l'objet d'accessoires.
mettre à jour :
Modifiez simplement React Component ReactApp comme ceci:
la source
Eh bien, le modèle le plus utilisé pour la logique réutilisable que j'ai rencontré est l'écriture d'un hook ou la création d'un fichier utils. Cela dépend de ce que vous voulez accomplir.
Comme si vous voulez valider les données de formulaire, je créerais un hook personnalisé nommé useForm.js et lui fournirais des données de formulaire et en retour, il me renverrait un objet contenant deux choses:
Vous pouvez certainement en retourner plus de choses au fur et à mesure que vous progressez.
Un autre exemple serait que vous vouliez extraire des informations d'une URL, puis je créerais un fichier utils pour celui-ci contenant une fonction et l'importerais si nécessaire:
la source