extjs - a initComponent() o no a initComponent()
extjs4 extjs4.1 (4)
Me cuesta crear una aplicación en ExtJS 4, y parte de eso es la confusión sobre cuándo configurar algo en initComponent () y cuándo no ...
Por ejemplo, en el propio documento MVC Application Architecture de Sencha, al crear por primera vez la vista de cuadrícula, definieron el almacenamiento en línea en el método initComponent (). (Consulte la sección "Definición de una vista")
Más abajo, cuando descartaron la tienda en una clase separada, movieron la definición fuera de initComponent (). Hay un comentario útil que llama la atención sobre este hecho, pero no hay explicación. (Consulte la sección Creación de un modelo y tienda)
Supongo que se supone que el motivo es obvio, pero me lo estoy perdiendo. ¿Alguna sugerencia?
Si no tiene un conocimiento profundo de cómo funciona el sistema de clases ExtJS, puede seguir esto:
Declare todos los tipos no primitivos en
initComponent()
.
Terminología
- Tipos primitivos : cadenas, booleanos, enteros, etc.
- No primitivos : matrices y objetos.
Explicación
Si el componente que amplía debe crearse más de una vez, las configuraciones no primitivas declaradas como una opción de configuración (fuera de initComponent
) se compartirán entre todas las instancias.
Debido a esto, muchas personas experimentaron problemas cuando se creó un componente extendido (generalmente una cuadrícula extendida) en más de una pestaña.
Este comportamiento se explica en la respuesta de sra a continuación y en este artículo de The Skirtle''s Den . Es posible que también desee leer esta pregunta SO .
He estado buscando una respuesta a la misma pregunta cuando terminé aquí y ver estas respuestas me decepcionó. Ninguno de estos responde la pregunta: initComponent () o constructor?
Es bueno saber que los objetos de opción de configuración de clase se comparten y que es necesario inicializarlos / procesarlos por instancia, pero el código puede ir al constructor, así como a la función initComponent ().
Mi suposición es que el constructor de la clase Component llama a initComponent () en algún lugar en el medio y no estaba muy equivocado: solo tenía que mirar el código fuente, en realidad es el constructor de AbstractComponent .
Entonces se ve así:
AbstractComponent/ctor:
- stuffBeforeIC()
- initComponent()
- stuffAfterIC()
Ahora, si extiende un Componente, obtendrá algo como esto:
constructor: function () {
yourStuffBefore();
this.callParent(arguments);
yourStuffAfter();
},
initComponent: function () {
this.callParent();
yourInitComp()
}
La orden final a la que se llaman es:
- yourStuffBefore()
- base''s ctor by callParent:
- stuffBeforeIC()
- initComponent:
- base''s initComponent by callParent
- yourInitComp()
- stuffAfterIC()
- yourStuffAfter()
Así que, al final, todo depende de si desea / necesita inyectar su código entre stuffBeforeIC y stuffAfterIC que puede buscar en el constructor de la clase que va a extender.
Normalmente abogo por tener tanta configuración como sea posible en las opciones de configuración de clase, porque se lee mejor y es más fácil sobrescribir en las subclases. Además de eso, existe una gran posibilidad de que en el futuro Sencha Cmd tenga un compilador de optimización, por lo que si mantiene el código declarativo, podría beneficiarse de las optimizaciones.
Comparar:
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();
Y:
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''
});
Tenga en cuenta cómo estos enfoques son muy diferentes. En el primer ejemplo, estamos codificando mucho: valores de propiedad del objeto, configuración de la tienda, nombre de la clase MyPanel cuando se usa; estamos prácticamente matando la idea de una clase porque se vuelve inextensible. En el segundo ejemplo, estamos creando una plantilla que se puede reutilizar muchas veces con una configuración posiblemente diferente; básicamente, de eso se trata todo el sistema de clases.
Sin embargo, la diferencia real es más profunda. En el primer caso, estamos difiriendo la configuración de la clase hasta el tiempo de ejecución, mientras que en el segundo caso estamos definiendo la configuración de la clase y aplicándola en fases muy distintas. De hecho, podemos decir fácilmente que el segundo enfoque introduce algo que JavaScript carece de forma nativa: fase de tiempo de compilación. Y nos da una plétora de posibilidades que se explotan en el código del marco en sí mismo; si quiere algunos ejemplos, eche un vistazo a Ext.app.Controller
y Ext.app.Application
en la última versión 4.2 beta.
Desde una perspectiva más práctica, el segundo enfoque es mejor porque es más fácil de leer y tratar. Una vez que comprenda la idea, se encontrará escribiendo todo su código de esa manera, porque es más fácil de esta manera.
Mírelo de esta manera: si escribiera una aplicación web antigua, generara HTML y cosas del lado del servidor, trataría de no tener ningún código HTML mezclado con el código, ¿verdad? Plantillas a la izquierda, código a la derecha. Eso es prácticamente lo mismo que los datos de initComponent
en initComponent
: seguro que funciona, hasta cierto punto. Luego se convierte en un plato de espagueti, difícil de mantener y extender. Ah, y probando todo eso! Yuck.
Ahora, hay momentos en los que necesita hacer algo con una instancia en tiempo de ejecución, a diferencia de un tiempo de definición de clase: el ejemplo clásico es aplicar detectores de eventos o control
llamadas en Controladores. Deberá tomar referencias de funciones reales de la instancia del objeto, y debe hacerlo en initComponent
o init
. Sin embargo, estamos trabajando para aliviar este problema; no debería haber ningún requisito estricto para codificar todo esto; Observable.on()
ya admite nombres de escuchas de cadenas y material MVC también, en breve.
Como dije en los comentarios anteriores, tendré que escribir un artículo o una guía para los documentos, explicando las cosas. Eso probablemente tendría que esperar hasta que se libere 4.2; Mientras tanto, esta respuesta debería arrojar algo de luz sobre el asunto, con suerte.
Primero tomaré una posición sobre mis Comentarios:
@AlexanderTokarev No me malinterpretes. No hablo de configuraciones de componentes, o mucho peor de las instancias y initComponent()
a initComponent()
, ese no es mi punto.
Ahora que pienso sobre esto
initComponent () debería resolver cualquier cosa requerida al momento en que se crea una instancia de esta clase. Ni mas ni menos.
Puede confundir una carga al definir las clases y la mayoría ocurre porque las personas no entienden cómo funciona el sistema de clases ExtJS. Como se trata de componentes, lo siguiente se centrará en ellos. También será un ejemplo simplificado que solo mostrará un tipo de error que he visto muchas veces.
Comencemos: tenemos un panel personalizado que hace muchas cosas ingeniosas. Eso hace surgir la necesidad de una configuración personalizada, lo llamamos foo
. Lo agregamos junto con nuestra opción de configuración predeterminada a la definición de clase para que podamos acceder a ella:
Ext.define(''Custom'', {
extend: ''Ext.panel.Panel'',
alias: ''widget.custpanel'',
foo: {
bar: null
},
initComponent: function() {
this.callParent(arguments);
}
});
Pero las cosas se ponen raras después de las pruebas. Los valores de nuestras configuraciones parecen cambiar mágicamente. Aquí hay un JSFiddle Lo que sucedió es que todas las instancias creadas se refieren a la misma instancia de foo
. Pero últimamente lo he hecho
store: {
fields: [ ... ],
proxy: {
type: ''direct'',
directFn: ''Direct.Store.getData''
}
}
con una tienda y eso funcionó. Entonces, ¿por qué no funciona?
La mayoría de las personas no ve ninguna diferencia entre este pequeño objeto foo
y una configuración (ExtJS) que es básicamente correcta porque ambos son objetos (instancias). Pero la diferencia es que todas las clases enviadas por sencha saben perfectamente qué propiedades de configuración esperan y cuidan de ellas.
Por ejemplo, StoreManager
resuelve la propiedad de tienda de una cuadrícula y, por lo tanto, puede ser:
- cadena
storeId
, o - instancia de tienda o
- almacenar objeto de configuración.
Durante la inicialización de la grilla, cualquiera de estos se resuelve y sobrescribe por una instancia de tienda real. Una tienda es solo un ejemplo. Supongo que el más conocido es el conjunto de elementos. Esta es una matriz en el momento de la definición y queda anulada para cada instancia con una MixedCollection (si no me equivoco).
Sí, existe una diferencia entre una definición de clase y la instancia creada a partir de ella. Pero tenemos que encargarnos de cualquier propiedad nueva que contenga una referencia como el foo
de arriba y eso no es tan complicado. Esto es lo que tenemos que hacer para solucionarlo por ejemplo
Ext.define(''Custom'', {
extend: ''Ext.panel.Panel'',
alias: ''widget.custpanel'',
foo: {
bar: null
},
initComponent: function() {
this.foo = Ext.apply({}, this.foo);
this.callParent(arguments);
}
});
Aquí está el JSFiddle
Ahora nos ocupamos de la configuración foo
cuando se crea una instancia. Ahora este ejemplo de foo
se simplifica y no siempre será tan fácil resolver una configuración.
Conclusión
¡Siempre escriba la definición de su clase como configuraciones! No deben contener ninguna instancia referida a excepción de la configuración simple y deben encargarse de resolverlas cuando se crea una instancia.
Renuncia
¡No pretendo cubrir todo con esta escritura realmente corta!