web-dev-qa-db-fra.com

React: Où étendre le prototype d'objet

J'ai créé une application React pure en utilisant create-react-app . Je voudrais étendre la classe String et l'utiliser dans un ou plusieurs composants . Par exemple:

String.prototype.someFunction = function () {
    //some code
}

(Vous voudrez peut-être jeter un œil à cette question pour en savoir plus sur l'extension des prototypes d'objets.)

Oui, je peux le définir à côté d'un composant et l'utiliser à l'intérieur. Mais quelle est la manière la meilleure et la plus propre?

Dois-je l'écrire en tant que class method ou à l'intérieur componentDidMount ou autre chose?

MODIFIER:

Est-il même "OK" d'étendre le prototype d'objet en React (ou en JavaScript))?

11
Ahmad Maleki

Réponse TLDR: Nulle part!

- Réponse nuancée -

Ce que j'essaie de faire est d'étendre des classes JavaScript pures, comme la classe String, qui est une tâche très courante en javascript

Est-il même "OK" d'étendre le prototype d'objet en React (ou en JavaScript))?

L'extension/la modification de prototypes natifs en JavaScript est un sujet controversé , et contrairement à ce que vous avez dit, ce n'est pas quelque chose que la plupart des développeurs professionnels font très souvent. Le consensus général est que l'extension des prototypes natifs JS est un anti-modèle de programmation à éviter , car il rompt le principe d'encapsulation et modifie l'état global. Cependant, comme avec de nombreuses règles, il peut y avoir de rares exceptions. Par exemple: vous travaillez sur un projet de jouet qui n'a pas besoin d'être de qualité de production, vous êtes le seul développeur à jamais toucher à cette base de code, ou votre code ne sera jamais une dépendance pour quelqu'un d'autre.

Si vous avez une très bonne raison et que vous savez vraiment ce que vous faites et que vous êtes pleinement conscient des conséquences potentielles de vos modifications sur les types/comportements de données natifs pour votre environnement d'exécution et vos dépendances, vous trouverez peut-être une utilisation valable cas pour cette pratique. Mais très probablement pas, ou du moins pas très souvent. Comme presque jamais.

Si vous êtes juste après le sucre de commodité/syntaxique, vous feriez mieux de tirer des fonctions utilitaires (des goûts de lodash, underscore ou ramda) et d'apprendre à pratiquer la composition fonctionnelle. Mais si vous êtes vraiment attaché au paradigme orienté objet, alors vous devriez probablement simplement "sous-classer" les types de données natifs plutôt que de les modifier .

Donc, plutôt que de muter le prototype d'une classe comme celui-ci:

String.prototype.somethingStupid = function () {
  return [].map.call(this, function(letter) {
    if ((Math.random() * 1) > .5) return letter.toUpperCase()
    else return letter.toLowerCase()
  }).join('')
}

console.log('This is a silly string'.somethingStupid())

Vous créeriez une sous-classe (ne fonctionne qu'avec la syntaxe de classe ES6), comme ceci:

class MyString extends String {
  constructor(x = '') {
    super(x)
    this.otherInstanceProp = ':)'
  }
  
  somethingStupid() {
    return [].map.call(this, function(letter) {
      if ((Math.random() * 1) > .5) return letter.toUpperCase()
      else return letter.toLowerCase()
    }).join('')
  }
}

const myStr = new MyString('This is a silly string')
console.log(myStr)
console.log(myStr.valueOf())
console.log(myStr.somethingStupid() + ', don\'t you think?')

Cette sous-classe fonctionnerait comme une chaîne intégrée dans tous les sens, sauf bien sûr que vous ne seriez pas en mesure d'écrire des littéraux MyString comme des littéraux String.

J'ai créé une application React pure en utilisant create-react-app. Je voudrais étendre la classe String et l'utiliser dans un ou plusieurs composants ... Oui, je peux la définir à côté d'un composant et mais quel est le moyen le plus propre et le plus propre? ... Dois-je l'écrire en tant que méthode de classe ou dans componentDidMount ou autre chose?

Parce que la modification de prototypes intégrés (en mutant des choses comme String.prototype) modifie l'état global de votre application, c'est quelque chose que vous ne voudrez exécuter qu'une seule fois et presque certainement avant que tout autre code ne s'exécute (car vous définissez l'état global du comportement des chaînes pour tout le code qui s'exécute après) . Donc, modifier des prototypes intégrés à partir d'une méthode d'instance de composant React n'a pas beaucoup de sens.

Si vous allez faire le sale boulot, je vous recommande de créer un module distinct pour chaque type natif que vous souhaitez modifier, et de conserver ces modules quelque part comme src/lib/extend-built-ins/ ou quelque chose, puis import comme première chose dans src/index.js. Vous n'auriez pas besoin d'exporter quoi que ce soit. Faire import src/lib/extend-built-ins/String.js exécutera le code, ce qui modifiera votre état global. Cela fournirait au moins une organisation décente et garantirait que votre environnement d'application est entièrement modifié avant l'exécution du reste du code de votre application. De cette façon, vous pouvez simplement utiliser vos types étendus dans toute votre application sans penser à les importer de quelque part.

Si vous allez suivre la route de sous-classement (class MyThing extends NativeThing), alors je vous recommanderais de définir de la même manière vos classes personnalisées dans des modules séparés quelque part comme src/lib/native-subclasses/. Mais dans ce cas, vous devrez import vos constructeurs de classe dans n'importe quel/chaque module où vous souhaitez les utiliser.

Cependant, si vous voulez développer du code propre, testable et refactorisable qui sera facile à comprendre pour les autres et votre futur, vous ne devriez pas faire ce genre de chose. Au lieu de cela, pensez à adopter les principes de programmation fonctionnelle de React et son écosystème. Tout le monde peut rapidement lire et comprendre une fonction pure, alors utilisez-les pour accomplir vos transformations de données et d'état plutôt que de vous fier à pour suivre les hacks comme modifier des objets globaux. Il peut être mignon et trivial de comprendre ce petit hack, mais le faire même une fois dans un projet vous encourage et encourage les autres à utiliser des raccourcis et des anti-modèles supplémentaires.

11
Derrick Beining