🦉 Краткая информация 🦉
Компоненты Owl в приложении используются для формиования (динамически) дерева компонентов.
Root
/ \
A B
/ \
C D
State(Состояние): каждый компонент может управлять своим локальным состоянием. Это простой ES6 класс, без каких либо правил:
class Counter extends Component {
static template = xml`
<button t-on-click="increment">
Click Me! [<t t-esc="state.value"/>]
</button>`;
state = { value: 0 };
increment() {
this.state.value++;
this.render();
}
}
Пример выше показывает компонет с локальным состоянием. Обратите внимане
что нет ничего необычного в объекте state
, и нам надо самостоятельно вызывать функцию render
каждый раз, когда мы вносим изменения в наше состояние. Такой подход очень быстро начне бесить
(и снижает эффектвность сли мы начинаем использовать его слишком часто).
Для этого есть способ лучше: использовать хук useState
,
который превращает объект в реактивную версию самого себя:
const { useState } = owl.hooks;
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++;
}
}
Обратите внимание, что обработчик t-on-click
можно даже заменить встроенным выражением:
<button t-on-click="state.value++">
Props(Свойства, пропсы): дочернему компоненту может часто
требоваться получать информацию от его родителя.
Это реализуется путем добавления необходимой информации в шаблон.
This
родителя будет доступен дочернему комненту в объекте props
.
Обратите внимание, что здесь есть важное правило:
информация, содержащаяся в объекте props
, не принадлежит дочернему компоненту
и никогда не должна им изменяться.
class Child extends Component {
static template = xml`<div>Hello <t t-esc="props.name"/></div>`;
}
class Parent extends Component {
static template = xml`
<div>
<Child name="'Owl'" />
<Child name="'Framework'" />
</div>`;
static components = { Child };
}
Communication(Коммуникация): существует несколько способов передачи информации между компонентами. Вот два наиболее важных:
- от родительского компонента - дочернему: используя объект
props
, - от дочернего компонента - родительскому: используя запуск событий(эвентов),
Следующий пример показывает оба механизма:
class OrderLine extends Component {
static template = xml`
<div t-on-click="add">
<div><t t-esc="props.line.name"/></div>
<div>Quantity: <t t-esc="props.line.quantity"/></div>
</div>`;
add() {
this.trigger("add-to-order", { line: this.props.line });
}
}
class Parent extends Component {
static template = xml`
<div t-on-add-to-order="addToOrder">
<OrderLine
t-foreach="orders"
t-as="line"
line="line" />
</div>`;
static components = { OrderLine };
orders = useState([
{ id: 1, name: "Coffee", quantity: 0 },
{ id: 2, name: "Tea", quantity: 0 },
]);
addToOrder(event) {
const line = event.detail.line;
line.quantity++;
}
}
В этом примере компонент OrderLine
инициирует событиеadd-to-order
.
Что в свою очередь породит событие DOM, которое начнет "всплывать" по DOM дереву.
Оно (событие) будет перехвачено родительским компонентом, который в свою очередь получит
строку (по ключу detail
) и затем увеличит ее количество. Вот детали того, ка работает
обработка событий.
Обратите внимание, и в случае, если бы компонент OrderLine
напрямую модифицировал объект line
. Однако это не очень хорошая практика:
это работает только потому, что объект props
, полученный дочерним компонентом, является реактивным,
поэтому дочерний компонент затем связан с реализацией родительского компонента.