45 votes

à initComponent () ou non à initComponent ()

J'ai du mal lors de la construction d'une application ExtJS 4, et une partie de la confusion sur le moment de configurer quelque chose dans initComponent() et quand ne pas le faire...

Par exemple, dans le Sencha est propre Application MVC Architecture doc, lors de la première création de l'affichage de la grille, ils ont défini la ligne de magasin dans le initComponent() la méthode. (Voir "Définition d'un point de Vue" de la section)

Plus bas, quand ils ont pris en compte les stocker dans une classe distincte, ils se sont déplacés à la définition en dehors de initComponent(). Il y a un commentaire qui attire l'attention sur ce fait, mais il n'y a pas d'explication. (Voir Création d'un Modèle et de Stocker de l'article)

Je suppose que la raison est censé être évident, mais je suis absente. Les pointeurs?

44voto

Izhaki Points 5883

Si vous n'avez pas une compréhension profonde de la façon dont ExtJS système de classe de travail, vous pouvez suivre ce:

Déclarer tous les non-types primitifs en initComponent().

La terminologie

  • Les types primitifs - les chaînes, les booléens, les entiers, etc.
  • Non-Primitives - tableaux & objets.

Explication

Si le composant que vous étendez est créé plus d'une fois, tous les non-primitif configs déclarée comme une option de configuration (à l'extérieur de initComponent) sera partagée entre toutes les instances.

De ce fait, de nombreuses personnes ont connu des problèmes lorsqu'une composante prolongée (généralement une extension de la grille) est créé sur plus d'un onglet.

Ce comportement est expliqué dans le sra de réponse ci-dessous et dans cette Skirtle Den article. Vous pouvez aussi lire cette SORTE de question.

22voto

sra Points 17565

Je vais d'abord prendre position sur mes Commentaires:

@AlexanderTokarev Ne m'obtenez pas le mal. Je ne parle pas des configurations de composants, ou pire encore d'instances et de les déplacer vers d' initComponent(), qui n'est pas mon point.

Maintenant ce que je pense sur ce sujet.

initComponent() devrait résoudre n'importe quoi du moment où une instance de cette classe est créée. Pas plus, pas moins.

Vous pouvez gâcher une charge lors de la définition des classes et la plupart de ce qui se passe parce que les gens ne comprennent pas comment le ExtJS classe-système fonctionne. Comme c'est sur les composants, la suite va se concentrer sur ceux-ci. Il sera également un exemple simplifié qui ne devrait montrer une sorte d'erreur que j'ai vu beaucoup de fois.

Commençons: Nous avons un panneau personnalisé qui fait beaucoup de chouettes choses. Cela nous amène à la nécessité d'une configuration personnalisée, nous l'appelons foo. Nous ajoutons avec notre configuration par défaut de l'option à la définition de la classe afin que nous puissions y accéder:

Ext.define('Custom', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.custpanel',

    foo: {
        bar: null  
    },

    initComponent: function() {
        this.callParent(arguments);
    }
});

Mais les choses deviennent étranges après les tests. Les valeurs de notre configurations semble changer comme par magie. Voici un JSFiddle Ce qui s'est passé, c'est que toutes les instances sont se référant à la même foo de l'instance. Mais dernièrement, je l'ai fait

store: {
    fields: [ ... ],
    proxy: {
        type: 'direct',
        directFn: 'Direct.Store.getData'
    }
}

avec un magasin et que travaillé. Alors pourquoi ne pas foo travail?

La plupart des gens ne voient pas la différence entre ce petit foo objet et un (ExtJS) config qui est en fait correct, parce que les deux sont des objets (instances). Mais la différence est que toutes les classes expédiés par sencha sais parfaitement bien la configuration des propriétés qu'ils attendent et prendre soin d'eux.

Par exemple, le magasin de la propriété d'une grille est résolue par l' StoreManager et peut donc être:

  • storeId chaîne de caractères, ou
  • instance de la banque ou de
  • stocker la configuration de l'objet.

Lors de l'initialisation de la grille de l'une de ces résolus et remplacée par une instance de la banque. Un magasin est juste un exemple. Je suppose que la plus connue est les éléments de tableau. C'est un tableau à la définition du temps et il obtient remplacé pour chaque instance d'un MixedCollection (si je ne me trompe pas).

Oui, il y a une différence entre la définition de la classe et de l'instance créée. Mais nous avons besoin de prendre soin de toute nouvelle propriété qui contient une référence comme l' foo à partir de ci-dessus et qui n'est pas si compliqué que ça. Voici ce que nous devons faire pour résoudre le problème de la foo exemple

Ext.define('Custom', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.custpanel',

    foo: {
        bar: null  
    },

    initComponent: function() {
        this.foo = Ext.apply({}, this.foo);
        this.callParent(arguments);
    }
});

Voici le JSFiddle

Maintenant, nous prenons soin de l' foo config lors d'une instance créée. Maintenant, c' foo exemple est simplifié et il ne sera pas toujours facile de résoudre une configuration.

Conclusion

Toujours écrire votre définition de classe que les configurations! Ils ne doivent pas contiennent toutes les instances visées à l'exception de la plaine de configuration et doit prendre soin de ces de les résoudre lorsqu'une instance créée.

Avertissement

Je n'ai pas la prétention de couvrir tous avec ce très court écrit!

14voto

Alex Tokarev Points 3178

J'ai l'habitude de plaider pour avoir autant de la configuration que possible dans la classe d'options de configuration, car il se lit mieux et est plus facile à remplacer dans les sous-classes. En outre, il est fort possible qu'à l'avenir, Sencha Cmd ont compilateur optimisant donc, si vous gardez votre code déclaratif, il a pu bénéficier d'optimisations.

Comparer:

Ext.define('MyPanel', {
    extend: 'Ext.grid.Panel',

    initComponent: function() {
        this.callParent();
        this.store = new Ext.data.Store({
            fields: [ ... ],
            proxy: {
                type: 'direct',
                directFn: Direct.Store.getData
            }
        });
        this.foo = 'bar';
    }
});

...

var panel = new MyPanel();

Et:

Ext.define('MyPanel', {
    extend: 'Ext.grid.Panel',
    alias: 'widget.mypanel',

    foo: 'bar',

    store: {
        fields: [ ... ],
        proxy: {
            type: 'direct',
            directFn: 'Direct.Store.getData'
        }
    }
});

...

var panel = Ext.widget({
    xtype: 'mypanel',
    foo: 'baz'
});

Notez comment ces approches sont très différentes. Dans le premier exemple, nous allons coder en dur beaucoup: propriété de l'objet de valeurs, magasin de configuration, MyPanel nom de la classe quand il est utilisé; nous sommes pratiquement tuer l'idée d'une classe, car il devient inextensible. Dans le deuxième exemple, nous sommes en train de créer un modèle qui peut être réutilisé de nombreuses fois, avec peut-être différente de la configuration, à la base, c'est ce que l'ensemble du système de classe est d'environ.

Cependant, la véritable différence se situe au plus profond. Dans le premier cas, nous sommes différant de la classe de configuration jusqu'à l'exécution, tandis que dans le second cas, nous avons la définition de la classe de configuration et l'application à très distinctement les différentes phases. En fait, nous pouvons facilement dire que la deuxième approche introduit quelque chose de JavaScript manque nativement: la compilation de phase. Et il nous donne une multitude de possibilités qui sont exploitées dans le cadre du code lui-même; si vous voulez quelques exemples, prendre un coup d'oeil à l' Ext.app.Controller et Ext.app.Application dans le dernier 4.2 beta.

De plus point de vue pratique, la deuxième approche est la meilleure parce que c'est plus facile à lire et traiter les. Une fois que vous avez saisi l'idée, vous trouverez vous-même écrit tout votre code comme ça, parce que c'est juste plus facile de cette façon.

Regardons cela de cette façon: si vous écrivez un style ancien de l'application Web, la génération de code HTML et des trucs sur le côté serveur, vous essayez de ne pas avoir un mélange de HTML avec le code, le feriez-vous? Les modèles de la gauche, du code de la droite. C'est pratiquement la même que coder en dur les données en initComponent: assurer qu'il fonctionne, jusqu'à un certain point. Puis il devient un bol de spaghetti, difficile à maintenir et à étendre. Oh, et de tester tout ça! Beurk.

Maintenant, il y sont des moments où vous devez faire quelque chose avec une instance au moment de l'exécution, par opposition à une définition de classe de l'époque - l'exemple classique est l'application des écouteurs d'événement, ou en appelant control chez les Contrôleurs. Vous aurez à prendre une fonction réelle des références à partir de l'instance de l'objet, et vous devez le faire dans initComponent ou init. Cependant, nous travaillons sur l'assouplissement ce problème - là ne devrait pas être dur obligation de coder en dur tout cela; Observable.on() prend déjà en charge de la chaîne de l'auditeur noms et MVC choses vont trop peu de temps.

Comme je l'ai dit dans les commentaires ci-dessus, je vais écrire un article ou un guide pour les docs, expliquer les choses. Qui aurait probablement attendre jusqu'à 4.2 est sorti; en attendant cette réponse devrait jeter une certaine lumière sur la question, je l'espère.

12voto

J'ai été à la recherche d'une réponse à la même question lorsque j'ai atterri ici et de voir que ces réponses m'a fait déçu. Aucun de ces répondu à la question: initComponent() ou constructeur?

Il est bon de savoir que la classe option de configuration des objets sont partagés et vous devez l'initialiser, un processus, par exemple, mais le code peut aller dans le constructeur ainsi que le initComponent() fonction.

Ma conjecture est que le constructeur de la classe appelle initComponent() quelque part dans le milieu et je n'étais pas très mal: Juste eu à regarder le code source, c'est en fait AbstractComponent du constructeur.

De sorte qu'il ressemble à ceci:

AbstractComponent/ctor:
- stuffBeforeIC()
- initComponent()
- stuffAfterIC()

Maintenant, si vous étendez un Composant, vous obtiendrez quelque chose comme ceci:

constructor: function () {
  yourStuffBefore();
  this.callParent(arguments);
  yourStuffAfter();
},
initComponent: function () {
  this.callParent();
  yourInitComp()
}

L'ordre final de ces appelés dans est:

- yourStuffBefore()
- base's ctor by callParent:
  - stuffBeforeIC()
  - initComponent:
    - base's initComponent by callParent
    - yourInitComp()
  - stuffAfterIC()
- yourStuffAfter()

Donc, en fin de compte, tout dépend si vous voulez/besoin d'injecter de votre code entre stuffBeforeIC et stuffAfterIC que vous pouvez consulter dans le constructeur de la classe que l'on va étendre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X