J'utilise des pratiques de programmation orientée objet depuis 25 ans et j'essaie de passer à la programmation fonctionnelle depuis 5 ans, mais je suis toujours concentré sur OOP lorsque j'essaie de faire quelque chose de complexe et, surtout maintenant que ES6 prend en charge la syntaxe décente OOP, c’est la manière naturelle pour moi de construire des choses.
J'apprends maintenant Redux et je comprends (c.f. Comment mettre des méthodes sur les objets en état Redux? ) qu'il est interdit de mettre des instances de classe dans vos réducteurs; et la méthode recommandée pour effectuer un calcul au-dessus de l'état d'un réducteur normal consiste à utiliser des sélecteurs (par exemple, via resélectionner). Et bien sûr, React recommande la composition plutôt que l’héritage ( https://facebook.github.io/react/docs/composition-vs-inheritance.html , Réagit aux classes redux oop ).
Mais y a-t-il une place dans l'écosystème React/Redux pour les objets de classe avec méthodes et héritage?
Je suppose que pour répondre à ma propre question, les classes OOP encouragent l'ajout de propriétés de données et d'opérations sur les données au même endroit, ce qui est agréable pour la lisibilité, mais ne correspond pas bien aux fonctions pures et données immuables.
Si je devais utiliser la POO, aurais-je besoin de dissuader de laisser mes instances persistantes et de conserver leur état pendant un certain temps? Par exemple, chaque fois que je veux en utiliser un, je l'instancie à partir des données du magasin, j'utilise les méthodes que je veux et je le jette? Cela pourrait empêcher une grande partie de l’élan d’utiliser les classes OOP. Mais si je garde les instances autour de moi, j'aurai des maux de tête en les maintenant synchronisées avec le magasin.
Alors, la solution est-elle de toujours utiliser les sélecteurs lorsque je suis tenté d'utiliser des méthodes et d'utiliser toujours la composition lorsque je suis tenté d'utiliser l'héritage? Plus précisément, je veux dire lors du stockage et de la manipulation de données stockées dans un magasin Redux pour une utilisation dans les composants React. Et, si oui, où devrait-il s'intégrer? Connecté à des sélecteurs? Immédiatement jetable comme je l'ai suggéré?
Ajout de mon cas d'utilisation pour plus de clarté: Mes données sont en gros un graphe: beaucoup d'objets avec beaucoup de propriétés et beaucoup de relations entre les objets. C'est en lecture seule, mais complexe. Mes objets s'appellent des "concepts".
Avant de prendre la décision (probablement stupide) de migrer vers Redux, j'ai utilisé des classes pour structurer et représenter des concepts, des ensembles de concepts et des relations entre des concepts. Mes classes incluaient une logique API asynchrone pour extraire des ensembles de concepts, des informations sur chaque concept et des informations sur d'autres concepts auxquels chaque concept est associé. Si l'utilisateur choisit de faire un zoom avant, les classes vont extraire et instancier de manière récursive de nouveaux ensembles de concepts. La documentation Redux recommande des structures plates normalisées pour les données imbriquées ( http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html ), ce qui est probablement judicieux pour le stockage, mais ma OOP modèle était bon pour parcourir des sections du graphique et d'autres choses. J'ai du mal à comprendre les sélecteurs et l'état immuable qui pourrait impliquer l'imbrication, éventuellement avec des cycles, ou le besoin de faire des appels asynchrones pour plus de données.
J'utilise avec succès https://redux-observable.js.org/ pour les éléments de l'API.
Peut-être que la réponse de @ Sulthan est juste: je devrais me sentir libre d'utiliser les techniques OOP dans mon application Redux. Mais cela semble toujours bizarre. Je ne peux pas garder mes objets à proximité, car si le magasin change (davantage de données est extraite, par exemple), mes objets peuvent devenir périmés. Si mes objets sont imbriqués mais que mon magasin est normalisé, je les instancierai (à partir des sélecteurs) lorsque j'en aurai besoin et je veillerai à ne pas les conserver ...
Je vais répondre à ma propre question en décrivant ce que j'ai fini par faire, même s'il est imparfait.
Premièrement, au lieu de la syntaxe habituelle des classes ES6, j'ai commencé à utiliser stampit , qui est plus laid que les classes ES6, mais beaucoup plus flexible.
Principalement, mes objets complexes existent sous deux formes:
J'utilise une convention de mettre un _underscore devant toutes les références aux objets simples. Ma "solution" est compliquée et mauvaise pour de nombreuses raisons, mais je pense qu'essayer d'utiliser des sélecteurs pour tout serait pire. Si vous êtes curieux, voici l'endroit dans mon code où je "gonflerai" mes objets plain store dans des instances: https://github.com/Sigfried/vocab-pop/blob/localstorage/src/ducks/conceptSet. js # L292
Transformer des POJO d'état redux en instances de classe (standard ou en stampit) est une idée terrible et quelqu'un aurait dû m'arrêter depuis longtemps.
J'aurais probablement dû accepter la réponse de @ markerikson, et peut-être que le problème Redux-ORM mérite d'être examiné, mais je voulais simplement dire de manière définitive: NE FAITES PAS CE QUE JE FAIS. (Je pense toujours que je suis si intelligent que de combler les "lacunes" des technologies que j'apprends avec des hacks intelligents - et puis je passe des mois douloureux à nettoyer le désordre une fois que j'ai compris pourquoi cette technologie n'incluait pas mon piratage informatique. première place.)
Depuis Composer un logiciel: Une introduction :
Ce que nous ne ferons pas, c’est de dire que la programmation fonctionnelle est meilleure que La programmation orientée objet, ou que vous devez en choisir une au lieu de . OOP vs FP est une fausse dichotomie. Toutes les applications JavaScript Réelles que j’ai vues au cours des dernières années mélangent intensément FP et OOP.
On dirait qu'il existe de bonnes façons de combiner FP et OOP, et il utilisera sans aucun doute des classes et une composition immuables sans beaucoup d'héritage. Cette série sur la composition ressemble à ce que j'avais besoin d'apprendre.
La réponse est que c'est possible mais fortement découragé et non idiomatique.
React s'appuie sur les classes et l'héritage à un seul niveau de React.Component
pour implémenter des composants avec état avec des cycles de vie, mais vous êtes officiellement déconseillé d'appliquer des niveaux d'héritage supplémentaires aux composants.
Redux est construit autour des principes de programmation fonctionnelle. Pour diverses raisons, vous êtes invité à conserver votre état en tant qu'objets et tableaux JS simples et à y accéder/le manipuler à l'aide de fonctions simples.
J'ai certainement vu de nombreuses bibliothèques qui ont essayé d'ajouter une couche OOP au-dessus de Redux (telles que des classes dont les méthodes sont transformées en créateurs et réducteurs d'action). Ces travail, mais vont certainement à l’encontre de l’esprit général de Redux.
J'utilise en fait une bibliothèque appelée Redux-ORM , qui ne vous permet de définir des classes Model qui agissent comme une façade sur les objets JS simples de votre magasin. Cependant, contrairement à beaucoup d'autres bibliothèques que j'ai vues, cela fonctionne avec Redux plutôt que d'essayer de modifier le comportement de Redux. J'ai discuté du fonctionnement de Redux-ORM, de mon utilisation et de la raison pour laquelle il reste raisonnablement idiomatique, dans mes billets de blog Practical Redux, Part 1: Notions fondamentales de Redux-ORM et Practical Redux, Part 2: Redux-ORM Concepts et techniques . Globalement, c'est un excellent outil pour aider à gérer les relations et les données normalisées dans votre magasin Redux.
Enfin, je travaille actuellement sur un article de blog qui traitera des limitations techniques actuelles imposées par Redux (et pourquoi), par rapport à la manière dont vous êtes destiné à utiliser Redux et à la manière dont il est possible d'utiliser Redux. . J'espère que cela se produira dans les prochaines semaines - gardez un œil sur http://blog.isquaredsoftware.com .
Cette question est un peu basée sur l'opinion mais concentrons-nous sur les points essentiels.
Il n'y a pas de contradiction entre la programmation fonctionnelle et la POO. Vous devez juste utiliser les mêmes modèles de programmation. Il n’ya aucun problème à utiliser des classes (avec héritage) dans la programmation fonctionnelle, si vous les gardez immuables.
Pour prouver mon argument, la bibliothèque populaire Immutable.js utilisée par de nombreuses personnes pour conserver l’état dans redux est composée de classes . Et ces classes ont un héritage (par exemple, OrderedSet extends Set
).
Notez également que la plupart des composants React
sont classes et utilisent également l’héritage (... extends React.Component
).