Componente
Un componente Owl es una clase pequeña que representa una parte de la interfaz de usuario. Forma parte de un árbol de componentes y tiene un entorno environment (env
), que se propaga desde un componente principal a sus componentes secundarios.
Los componentes OWL se definen mediante la herencia de la clase Component
. Por ejemplo, así es como se podría implementar un componente Counter
:
const { Component, xml, useState } = owl;
class Counter extends Component { static template = xml` <button t-on-click="increment"> Click Me! [<t t-esc="state.value"/>] </button>`;
state = useState({ value: 0 });
increment() { this.state.value++; }}
En este ejemplo, utilizamos el ayudante xml
para definir plantillas en línea y el gancho useState
, que devuelve una versión reactiva de su argumento (consulte la página sobre reactividad).
Propiedades y métodos
La clase Componente
tiene una API muy pequeña.
-
env (object)
: el componente environment -
props (object)
: Este es un objeto que contiene todas las props dadas por el componente padre a un componente hijo.Tenga en cuenta que las “props” pertenecen al elemento principal, no al componente. Por lo tanto, el componente nunca debería modificarlos (de lo contrario, corre el riesgo de que se produzcan efectos no deseados, ya que el elemento principal puede no estar al tanto del cambio).
El componente padre puede modificar dinámicamente las
props
. En ese caso, el componente pasará por los siguientes métodos de ciclo de vida:willUpdateProps
,willPatch
ypatched
. -
render(deep[=false])
: Al llamar a este método directamente se producirá una nueva renderización. Tenga en cuenta que con el sistema de reactividad, debería ser poco frecuente tener que hacerlo manualmente. Además, la operación de renderización es asincrónica, por lo que el DOM solo se actualizará un poco más tarde (en el siguiente cuadro de animación, si ningún componente retrasa la renderización).De forma predeterminada, el renderizado iniciado por este método se detendrá en cada componente secundario si sus propiedades son (superficiales) iguales. Para forzar un renderizado a actualizar todos los componentes secundarios, se puede usar el argumento opcional
deep
. Tenga en cuenta que el valor del argumentodeep
debe ser un valor booleano, no un valor verdadero.
Propiedades estáticas
-
template (string)
: Este es el nombre de la plantilla que representará el componente. Tenga en cuenta que hay un asistentexml
para facilitar la definición de una plantilla en línea. -
components (object, optional)
: Si se proporciona, este es un objeto que contiene las clases de cualquier subcomponente que necesite la plantilla.class ParentComponent extends owl.Component {static components = { SubComponent };} -
props (object, optional)
: Si se proporciona, este es un objeto que describe el tipo y la forma de las propiedades (reales) proporcionadas al componente. Si el modo Owl esdev
, se utilizará para validar las propiedades cada vez que se cree o actualice el componente. Consulte Validación de propiedades para obtener más información.class Counter extends owl.Component {static props = {initialValue: Number,optional: true,};} -
defaultProps (object, optional)
: Si se proporciona, este objeto define valores predeterminados para las propiedades (de nivel superior). Siempre que se proporcionenprops
al objeto, se modificarán para agregar el valor predeterminado (si falta). Tenga en cuenta que no cambia el objeto inicial, se creará un nuevo objeto en su lugar. Consulte propiedades predeterminadas para obtener más información.class Counter extends owl.Component {static defaultProps = {initialValue: 0,};}
Ciclo de Vida
Un sistema de componentes sólido y robusto necesita un sistema de ciclo de vida completo para ayudar a los desarrolladores a escribir componentes. A continuación, se incluye una descripción completa del ciclo de vida de un componente Owl:
Método | Hook | Descripción |
---|---|---|
setup | none | configuración |
willStart | onWillStart | asíncrono, antes de la primera renderización |
willRender | onWillRender | Justo antes de que se renderice el componente |
rendered | onRendered | Justo después de que se renderiza el componente |
mounted | onMounted | Justo después de que el componente se renderiza y se agrega al DOM |
willUpdateProps | onWillUpdateProps | asíncrono, antes de actualizar las propiedades |
willPatch | onWillPatch | Justo antes de que se parchee el DOM |
patched | onPatched | Justo después de que se parchea el DOM |
willUnmount | onWillUnmount | Justo antes de eliminar el componente del DOM |
willDestroy | onWillDestroy | Justo antes de que se destruya el componente |
error | onError | Captura y gestiona errores (Ver Manejo de Errores) |
setup
setup se ejecuta justo después de que se construye el componente. Es un método de ciclo de vida, muy similar al constructor, excepto que no recibe ningún argumento.
Es el lugar adecuado para llamar a las funciones de gancho. Tenga en cuenta que una de las principales razones para tener el gancho setup
en el ciclo de vida del componente es hacer posible aplicarle parches. Es una necesidad común en el ecosistema de Odoo.
setup() { useSetupAutofocus();}
willStart
willStart
es un gancho asincrónico que se puede implementar para realizar alguna acción (la mayoría de las veces asincrónica) antes de la representación inicial de un componente.
Se llamará exactamente una vez antes de la renderización inicial. Es útil en algunos casos, por ejemplo, para cargar recursos externos (como una biblioteca JS) antes de que se renderice el componente. Otro caso de uso es cargar datos desde un servidor.
El gancho onWillStart
se utiliza para registrar una función que se ejecutará en este momento:
setup() { onWillStart(async () => { this.data = await this.loadData() }); }
En este punto, el componente aún no se ha renderizado. Tenga en cuenta que el código willStart
lento ralentizará la renderización de la interfaz de usuario. Por lo tanto, se debe tener cuidado para que este método sea lo más rápido posible.
Tenga en cuenta que si hay más de una devolución de llamada onWillStart
registrada, todas se ejecutarán en paralelo.
willRender
No es habitual, pero puede suceder, que sea necesario ejecutar código justo antes de que se renderice un componente (más precisamente, cuando se ejecuta su función de plantilla compilada). Para ello, se puede utilizar el gancho onWillRender
:
setup() { onWillRender(() => { // do something }); }
El gancho willRender
se llama justo antes de renderizar las plantillas, primero las principales y luego las secundarias.
rendered
No es habitual, pero puede suceder, que sea necesario ejecutar código justo después de que se renderiza un componente (más precisamente, cuando se ejecuta su función de plantilla compilada). Para ello, se puede utilizar el gancho onRendered
:
setup() { onRendered(() => { // do something }); }
Los ganchos rendered
se llaman justo después de renderizar las plantillas, primero el padre y luego los hijos. Tenga en cuenta que en este momento, es posible que el DOM real aún no exista (si es la primera renderización) o que aún no se haya actualizado. Este será el DOM en el siguiente cuadro de animación tan pronto como todos los componentes estén listos.
mounted
El gancho mounted
se llama cada vez que se adjunta un componente al DOM, después de la representación inicial. En este punto, el componente se considera activo. Este es un buen lugar para agregar algunos oyentes o para interactuar con el DOM, si el componente necesita realizar alguna medida, por ejemplo.
Es lo opuesto de “willUnmount”. Si un componente ha sido montado, siempre será desmontado en algún momento en el futuro.
El método montado se llamará de forma recursiva en cada uno de sus hijos. Primero, los hijos, luego los padres.
Está permitido (pero no se recomienda) modificar el estado en el gancho mounted
. Si lo hace, se volverá a renderizar, lo que no será perceptible para el usuario, pero ralentizará ligeramente el componente.
El gancho onMounted
se utiliza para registrar una función que se ejecutará en este momento:
setup() { onMounted(() => { // do something here }); }
willUpdateProps
willUpdateProps
es un gancho asincrónico, que se llama justo antes de que se establezcan nuevas propiedades. Esto es útil si el componente necesita realizar una tarea asincrónica, dependiendo de las propiedades (por ejemplo, suponiendo que las propiedades son algún Id de registro, obteniendo los datos del registro).
El gancho onWillUpdateProps
se utiliza para registrar una función que se ejecutará en este momento:
setup() { onWillUpdateProps(nextProps => { return this.loadData({id: nextProps.id}); }); }
Tenga en cuenta que recibe las siguientes propiedades para el componente.
Este gancho no se llama durante la primera renderización (pero se llama a willStart
y realiza una tarea similar). Además, como la mayoría de los ganchos, se llama en el orden habitual: primero los padres, luego los hijos.
willPatch
El gancho willPatch se llama justo antes de que comience el proceso de aplicación de parches al DOM. No se llama en la representación inicial. Esto resulta útil para leer información del DOM. Por ejemplo, la posición actual de la barra de desplazamiento.
Tenga en cuenta que aquí no se permite modificar el estado. Este método se llama justo antes de un parche DOM real y solo está pensado para usarse para guardar algún estado DOM local. Además, no se llamará si el componente no está en el DOM.
El gancho onWillPatch
se utiliza para registrar una función que se ejecutará en este momento:
setup() { onWillPatch(() => { this.scrollState = this.getScrollSTate(); }); }
willPatch
se llama en el orden habitual padre -> hijos.
patched
Este gancho se llama siempre que un componente realmente actualizó su DOM (probablemente a través de un cambio en su estado/propiedades o entorno).
Este método no se llama en la renderización inicial. Es útil para interactuar con el DOM (por ejemplo, a través de una biblioteca externa) siempre que se haya aplicado un parche al componente. Tenga en cuenta que este gancho no se llamará si el componente no está en el DOM.
El gancho onPatched
se utiliza para registrar una función que se ejecutará en este momento:
setup() { onPatched(() => { this.scrollState = this.getScrollSTate(); }); }
Es posible actualizar el estado del componente en este gancho, pero no se recomienda. Hay que tener cuidado, porque las actualizaciones aquí crearán una representación adicional, que a su vez provocará otras llamadas al método patched
. Por lo tanto, debemos tener especial cuidado para evitar ciclos infinitos.
Al igual que mounted
, el gancho patched
se llama en el orden: primero los hijos, luego los padres.
willUnmount
willUnmount
es un gancho que se llama cada vez justo antes de que se desmonte un componente del DOM. Este es un buen lugar para eliminar oyentes, por ejemplo.
El gancho onWillUnmount
se utiliza para registrar una función que se ejecutará en este momento:
setup() { onMounted(() => { // add some listener }); onWillUnmount(() => { // remove listener }); }
Este es el método opuesto a mounted
. Tenga en cuenta que si se destruye un componente antes de montarlo, es posible que no se llame al método willUnmount
.
Los ganchos padres willUnmount
se llamarán antes que los hijos.
willDestroy
A veces, los componentes necesitan realizar alguna acción en la configuración
y limpiarla cuando están inactivos. Sin embargo, el gancho willUnmount
no es apropiado para la operación de limpieza, ya que el componente puede destruirse antes de que se haya montado. El gancho willDestroy
es útil en esa situación, ya que siempre se llama.
El gancho onWillDestroy
se utiliza para registrar una función que se ejecutará en este momento:
setup() { onWillDestroy(() => { // do some cleanup }); }
Los ganchos willDestroy
se llaman primero en los hijos y luego en los padres.
onError
Lamentablemente, puede ocurrir que los componentes fallen durante la ejecución. Esta es una triste realidad y es por eso que Owl necesita proporcionar una forma de manejar estos errores.
El gancho onError
es útil cuando necesitamos interceptar y reaccionar adecuadamente ante errores que ocurren en algunos subcomponentes. Consulte la página sobre manejo de errores para obtener más detalles.
setup() { onError(() => { // do something }); }
Subcomponentes
Es conveniente definir un componente utilizando otros (sub)componentes. Esto se llama composición y es muy eficaz en la práctica. Para hacerlo en Owl, uno puede simplemente usar una etiqueta que comience con una letra mayúscula en su plantilla y registrar la clase del subcomponente en su objeto estático components
:
class Child extends Component { static template = xml`<div>child component <t t-esc="props.value"/></div>`;}
class Parent extends Component { static template = xml` <div> <Child value="1"/> <Child value="2"/> </div>`;
static components = { Child };}
Este ejemplo también muestra cómo se puede pasar información del componente principal al componente secundario, como propiedades. Consulte la sección props para obtener más información.
Subcomponentes dinámicos
No es habitual, pero a veces necesitamos un nombre de componente dinámico. En este caso, también se puede utilizar la directiva t-component
para aceptar valores dinámicos. Esta debe ser una expresión que evalúe una clase de componente. Por ejemplo:
class A extends Component { static template = xml`<div>child a</div>`;}class B extends Component { static template = xml`<span>child b</span>`;}class Parent extends Component { static template = xml`<t t-component="myComponent"/>`;
state = useState({ child: "a" });
get myComponent() { return this.state.child === "a" ? A : B; }}
status
helper
A veces resulta conveniente tener una forma de averiguar en qué estado se encuentra actualmente un componente. Para ello, se puede utilizar el asistente status
:
const { status } = owl;// assume component is an instance of a Component
console.log(status(component));// logs either:// - 'new', if the component is new and has not been mounted yet// - 'mounted', if the component is currently mounted// - 'cancelled', if the component has not been mounted yet but will be destroyed soon// - 'destroyed' if the component is currently destroyed