1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2025-04-01 19:55:53 +02:00
This commit is contained in:
Jan Andrle 2025-03-05 18:59:37 +01:00
parent 5a6f011823
commit 05413cb2bb
3 changed files with 78 additions and 9 deletions

View File

@ -13,16 +13,20 @@ function Counter() {
count.set(count.get() + 1);
// NEVER EVER
// count = S(count.get() + 1);
// THE HOST IS PROBABLY DIFFERENT THAN
// YOU EXPECT AND SIGNAL MAY BE
// UNEXPECTEDLY REMOVED!!!
host().querySelector("button").disabled = count.get() >= 10;
};
// NEVER EVER
// setTimeout(()=> {
// const wrong= S(0);
// // THE HOST IS PROBABLY DIFFERENT THAN
// // YOU EXPECT AND OBSERVABLES MAY BE
// // UNEXPECTEDLY REMOVED!!!
// counterText.textContent= "Count: " + wrong.get();
// }, 1000);
setTimeout(()=> {
// ok, BUT consider extract to separate function
// see section below for more info
scope.push();
const ok= S(0);
scope.pop();
S.on(ok, console.log);
setInterval(()=> ok.set(ok.get() + 1), 100);
}, 100);
return el("div").append(
counterText,

View File

@ -157,6 +157,71 @@ function MyComponent() {
),
),
el(h3, t`Advanced: Custom Scoping Control`),
el("p").append(...T`
In more complex applications, you may need finer control over scopes. DDE provides
manual scope control mechanisms through ${el("code", "scope.push()")} and ${el("code", "scope.pop()")}.
`),
el("div", { className: "function-table" }).append(
el("h4", t`Manual Scope Control API`),
el("dl").append(
el("dt", t`scope.push()`),
el("dd", t`Creates a new scope and makes it the current active scope. All signals and subscriptions
created after this call will be associated with this new scope.`),
el("dt", t`scope.pop()`),
el("dd", t`Restores the previous scope that was active before the matching push() call.`),
el("dt", t`scope.current()`),
el("dd", t`Returns the currently active scope object.`),
el("dt", t`scope.withScope(callback)`),
el("dd", t`Executes the callback function within a temporary scope, then automatically restores the previous scope.
Safer than manual push/pop for most use cases.`)
)
),
el("p").append(...T`
Custom scoping is particularly useful for:
`),
el("ul").append(
el("li", t`Isolating signal dependencies in async operations`),
el("li", t`Creating detached reactive logic that shouldn't be tied to a component's lifecycle`),
el("li", t`Building utilities that work with signals but need scope isolation`)
),
el(code, { content: `// Inside a component
function SomeComponent() {
// Create an isolated scope for a specific operation
scope.push(); // Start new scope
// These signals are in the new scope
const isolatedCount = S(0);
const isolatedDerived = S(() => isolatedCount.get() * 2);
// Clean up by returning to previous scope
scope.pop();
// Alternative: Use withScope for automatic scope management
scope.withScope(() => {
// This code runs in an isolated scope
const tempSignal = S("temporary");
// No need for pop() - scope is restored automatically
});
// Rest of component remains in the original scope
return el("div");
}`, page_id }),
el("div", { className: "warning" }).append(
el("p").append(...T`
${el("strong", "Be careful with manual scope control!")} Always ensure you have matching push() and pop() calls,
preferably in the same function. Unbalanced scope management can lead to memory leaks or unexpected behavior.
`),
el("p").append(...T`
For most use cases, prefer using the automatic scope management provided by components.
Manual scope control should be considered an advanced feature.
`)
),
el(h3, t`Best Practices for Scopes and Components`),
el("ol").append(
el("li").append(...T`

2
index.d.ts vendored
View File

@ -232,7 +232,7 @@ export const scope: {
state: Scope[],
/** Adds new child scope. All attributes are inherited by default. */
push(scope: Partial<Scope>): ReturnType<Array<Scope>["push"]>,
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>,
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>,
/** Removes last/current child scope. */