mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] hooks: add onWillPatch and onPatched
This commit also changes the behaviour of willPatch and patched: they no longer transfer data from one to the other, because it can be done cleanly by hooks and a closure. closes #307
This commit is contained in:
+8
-13
@@ -329,9 +329,6 @@ before an actual DOM patch, and is only intended to be used to save some local
|
||||
DOM state. Also, it will not be called if the component is not in the DOM (this can
|
||||
happen with components with `t-keepalive`).
|
||||
|
||||
The return value of this method will be given as the first argument of the
|
||||
corresponding `patched` call.
|
||||
|
||||
#### `patched(snapshot)`
|
||||
|
||||
This hook is called whenever a component did actually update its DOM (most
|
||||
@@ -342,8 +339,6 @@ with the DOM (for example, through an external library) whenever the
|
||||
component was patched. Note that this hook will not be called if the compoent is
|
||||
not in the DOM (this can happen with components with `t-keepalive`).
|
||||
|
||||
The `snapshot` parameter is the result of the previous `willPatch` call.
|
||||
|
||||
Updating the compoent state in this hook is possible, but not encouraged.
|
||||
One need to be careful, because updates here will cause rerender, which in
|
||||
turn will cause other calls to patched. So, we need to be particularly
|
||||
@@ -1219,7 +1214,7 @@ class Node extends Component {
|
||||
</t>
|
||||
</g>
|
||||
`;
|
||||
static components = { Node };
|
||||
static components = { Node };
|
||||
}
|
||||
|
||||
class RootNode extends Component {
|
||||
@@ -1230,12 +1225,12 @@ class RootNode extends Component {
|
||||
`;
|
||||
static components = { Node };
|
||||
graph = {
|
||||
label: "a",
|
||||
children: [
|
||||
{label: "b"},
|
||||
{label: "c", children: [{label: "d"}, {label: "e"}]},
|
||||
{label: "f", children: [{label: "g"}]},
|
||||
]
|
||||
label: "a",
|
||||
children: [
|
||||
{ label: "b" },
|
||||
{ label: "c", children: [{ label: "d" }, { label: "e" }] },
|
||||
{ label: "f", children: [{ label: "g" }] }
|
||||
]
|
||||
};
|
||||
}
|
||||
```
|
||||
@@ -1247,4 +1242,4 @@ here: the `Node` component uses itself as a subcomponent.
|
||||
Note that since SVG needs to be handled in a specific way (its namespace needs
|
||||
to be properly set), there is a small constraint for Owl components: if an owl
|
||||
component is supposed to be a part of an svg graph, then its root node needs to
|
||||
be a `g` tag, so Owl can properly set the namespace.
|
||||
be a `g` tag, so Owl can properly set the namespace.
|
||||
|
||||
+52
-8
@@ -3,7 +3,8 @@
|
||||
## Content
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Example](#example)
|
||||
- [Example: Mouse Position](#example-mouse-position)
|
||||
- [Example: Autofocus](#example-autofocus)
|
||||
- [Reference](#reference)
|
||||
- [One Rule](#one-rule)
|
||||
- [`useState`](#usestate)
|
||||
@@ -28,7 +29,7 @@ Hooks works beautifully with Owl components: they solve the problems mentioned
|
||||
above, and in particular, they are the perfect way to make your component
|
||||
reactive.
|
||||
|
||||
## Example
|
||||
## Example: mouse position
|
||||
|
||||
Here is the classical example of a non trivial hook to track the mouse position.
|
||||
|
||||
@@ -57,9 +58,9 @@ function useMouse() {
|
||||
// Main root component
|
||||
class App extends owl.Component {
|
||||
static template = xml`
|
||||
<div t-name="App">
|
||||
<div>Mouse: <t t-esc="mouse.x"/>, <t t-esc="mouse.y"/></div>
|
||||
</div>`;
|
||||
<div t-name="App">
|
||||
<div>Mouse: <t t-esc="mouse.x"/>, <t t-esc="mouse.y"/></div>
|
||||
</div>`;
|
||||
|
||||
// this hooks is bound to the 'mouse' property.
|
||||
mouse = useMouse();
|
||||
@@ -69,6 +70,49 @@ class App extends owl.Component {
|
||||
Note that we use the prefix `use` for hooks, just like in React. This is just
|
||||
a convention.
|
||||
|
||||
## Example: autofocus
|
||||
|
||||
Hooks can be combined to create the desired effect. For example, the following
|
||||
hook combines the `useRef` hook with the `onPatched` and `onMounted` functions
|
||||
to create an easy way to focus an input whenever it appears in the DOM:
|
||||
|
||||
```js
|
||||
function useAutofocus(name) {
|
||||
let ref = useRef(name);
|
||||
let isInDom = false;
|
||||
function updateFocus() {
|
||||
if (!isInDom && ref.el) {
|
||||
isInDom = true;
|
||||
ref.el.focus();
|
||||
} else if (isInDom && !ref.el) {
|
||||
isInDom = false;
|
||||
}
|
||||
}
|
||||
onPatched(updateFocus);
|
||||
onMounted(updateFocus);
|
||||
}
|
||||
```
|
||||
|
||||
This hook takes the name of a valid `t-ref` directive, which should be present
|
||||
in the template. It then checks whenever the component is mounted or patched if
|
||||
the reference is not valid, and in this case, it will focus the node element.
|
||||
This hook can be used like this:
|
||||
|
||||
```js
|
||||
class SomeComponent extends Component {
|
||||
static template = xml`
|
||||
<div>
|
||||
<input />
|
||||
<input t-ref="myinput"/>
|
||||
</div>`;
|
||||
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
useAutofocus("myinput");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
### One rule
|
||||
@@ -79,21 +123,21 @@ constructor (or in class fields):
|
||||
```js
|
||||
// ok
|
||||
class SomeComponent extends Component {
|
||||
state = useState({value: 0});
|
||||
state = useState({ value: 0 });
|
||||
}
|
||||
|
||||
// also ok
|
||||
class SomeComponent extends Component {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.state = useState({value: 0});
|
||||
this.state = useState({ value: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
// not ok: this is executed after the constructor is called
|
||||
class SomeComponent extends Component {
|
||||
async willStart() {
|
||||
this.state = useState({value: 0});
|
||||
this.state = useState({ value: 0 });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user