Skip to content

Side Effect Isolation

The signal and lifecycle APIs can cause side effects such as tracking a signal access or registering a teardown hook.

The isolate function can be used to run arbitrary code in isolation from signal access tracking and the current lifecycle.

import { isolate } from "rvx";

isolate(() => {
    // Some code with side effects...
});
import { isolate } from "./rvx.js";

isolate(() => {
    // Some code with side effects...
});

Lifecycle

Teardown hooks are leaked as if teardown was called outside of any context:

import { capture, teardown, isolate } from "rvx";

capture(() => {
    // This will be captured:
    teardown(() => {});

    isolate(() => {
        // This will leak:
        teardown(() => {});
    });
});
import { capture, teardown, isolate } from "./rvx.js";

capture(() => {
    // This will be captured:
    teardown(() => {});

    isolate(() => {
        // This will leak:
        teardown(() => {});
    });
});

To isolate only the lifecycle, you can also use uncapture, but this will not trigger leak detection.

Signals

Signal accesses are not tracked as if the signal was accessed outside of any observer.

import { effect, isolate, track } from "rvx";

effect(() => {
    // This is tracked:
    signalA.access();

    isolate(() => {
        // This is ignored:
        signalB.access();

        track(() => {
            // This is also ignored:
            signalC.access();
        });
    });
});
import { effect, isolate, track } from "./rvx.js";

effect(() => {
    // This is tracked:
    signalA.access();

    isolate(() => {
        // This is ignored:
        signalB.access();

        track(() => {
            // This is also ignored:
            signalC.access();
        });
    });
});

To only control if signal accesses are tracked, use track and untrack instead.

Non Isolated APIs

Batches are not isolated as this could lead to inconsistent signal access tracking:

import { batch, isolate } from "rvx";

batch(() => {
    // This is part of the batch:
    a.value++;

    isolate(() => {
        // This is also part of the batch:
        b.value++;
    });
});

The isolate function is transparent to all contexts for performance reasons:

import { Context, isolate } from "rvx";

const EXAMPLE = new Context(42);

EXAMPLE.inject(77, () => {
    isolate(() => {
        EXAMPLE.value; // 77
    });
});
import { Context, isolate } from "./rvx.js";

const EXAMPLE = new Context(42);

EXAMPLE.inject(77, () => {
    isolate(() => {
        EXAMPLE.value; // 77
    });
});

In case you also need to isolate all contexts, isolate can be combined with Context.window:

import { Context, isolate } from "rvx";

isolate(Context.window, [], () => {
    // ...
});
import { Context, isolate } from "./rvx.js";

isolate(Context.window, [], () => {
    // ...
});