Skip to content

Commit 7856ceb

Browse files
committed
Fix #107 - Export a detach utility for reactivivity
1 parent 6ad4373 commit 7856ceb

6 files changed

Lines changed: 46 additions & 26 deletions

File tree

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const {
4747
### uhtml/preactive example
4848

4949
```js
50-
import { render, html, signal } from 'uhtml/preactive';
50+
import { render, html, signal, detach } from 'uhtml/preactive';
5151

5252
const count = signal(0);
5353

@@ -56,4 +56,9 @@ render(document.body, () => html`
5656
Clicks: ${count.value}
5757
</button>
5858
`);
59-
```
59+
60+
// stop reacting to signals in the future
61+
setTimeout(() => {
62+
detach(document.body);
63+
}, 10000);
64+
```

esm/reactive.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Hole, html, svg, htmlFor, svgFor, attr } from './keyed.js';
22

3-
import reactive from './render/reactive.js';
3+
import { detach, attach } from './render/reactive.js';
44

5-
export { Hole, reactive, html, svg, htmlFor, svgFor, attr };
5+
export { Hole, detach, attach, html, svg, htmlFor, svgFor, attr };

esm/reactive/preact.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export * from '@preact/signals-core';
2-
export { Hole, html, svg, htmlFor, svgFor, attr } from '../reactive.js';
2+
export { Hole, html, svg, htmlFor, svgFor, detach, attr } from '../reactive.js';
33

44
import { effect } from '@preact/signals-core';
5-
import { reactive } from '../reactive.js';
6-
export const render = reactive(effect);
5+
import { attach } from '../reactive.js';
6+
export const render = attach(effect);

esm/reactive/signal.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export * from '@webreflection/signal';
2-
export { Hole, html, svg, htmlFor, svgFor, attr } from '../reactive.js';
2+
export { Hole, html, svg, htmlFor, svgFor, detach, attr } from '../reactive.js';
33

44
import { effect } from '@webreflection/signal';
5-
import { reactive } from '../reactive.js';
6-
export const render = reactive(effect);
5+
import { attach } from '../reactive.js';
6+
export const render = attach(effect);

esm/render/reactive.js

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ const effects = new WeakMap;
1313
*/
1414
const onGC = dispose => dispose();
1515

16-
export default effect => {
16+
let remove = true;
17+
18+
/**
19+
* @param {Function} effect the reactive `effect` callback provided by a 3rd party library.
20+
* @returns
21+
*/
22+
export const attach = effect => {
1723
/**
1824
* Render with smart updates within a generic container.
1925
* If the `what` is a function, it automatically create
@@ -24,20 +30,28 @@ export default effect => {
2430
* @returns {T}
2531
*/
2632
return (where, what) => {
27-
let dispose = effects.get(where);
28-
if (dispose) {
29-
drop(dispose);
30-
dispose();
31-
}
32-
if (typeof what === 'function') {
33-
const wr = new WeakRef(where);
34-
dispose = effect(() => { render(wr.deref(), what(), false) });
35-
effects.set(where, dispose);
36-
return create(dispose, onGC, { return: where });
37-
}
38-
else {
39-
effects.delete(where);
40-
return render(where, what, false);
41-
}
33+
remove = typeof what !== 'function';
34+
detach(where);
35+
36+
if (remove) return render(where, what, false);
37+
remove = true;
38+
39+
const wr = new WeakRef(where);
40+
const dispose = effect(() => { render(wr.deref(), what(), false) });
41+
effects.set(where, dispose);
42+
return create(dispose, onGC, { return: where });
4243
};
4344
};
45+
46+
/**
47+
* Allow manual cleanup of subscribed signals.
48+
* @param {Element} where a reference container previously used to render signals.
49+
*/
50+
export const detach = where => {
51+
const dispose = effects.get(where);
52+
if (dispose) {
53+
if (remove) effects.delete(where);
54+
drop(dispose);
55+
dispose();
56+
}
57+
};

esm/render/shared.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const known = new WeakMap;
1010
* @template T
1111
* @param {T} where the DOM node where to render content
1212
* @param {(() => Hole) | Hole} what the hole to render
13+
* @param {boolean} check does a `typeof` check (internal usage).
1314
* @returns
1415
*/
1516
export default (where, what, check) => {

0 commit comments

Comments
 (0)