Direct Answers
What ensures a fetch initiated in an effect is aborted before the reactive owner disposes? Only an explicit onCleanup callback that calls abort() on an AbortController whose signal was passed to fetch. SolidJS provides no automatic linkage between effect disposal and in-flight network requests.
Whether a timer set inside createEffect still fires after onCleanup callbacks have run. Yes. setTimeout/setInterval callbacks execute in a later macrotask after disposal completes unless the cleanup callback calls clearTimeout/clearInterval.
Influence of a schema mutation mid-effect on the disposal sequence in recent SolidJS versions. None. Signal writes occurring during disposal do not re-trigger effects or delay cleanup. The disposal sequence is a single synchronous pass over registered cleanups, then owner disposal.
Confirmed Disposal Mechanics
onCleanup registers callbacks to the current reactive owner.
- At disposal, all registered cleanups run synchronously in LIFO order, before the owner is marked disposed.
- Cleanups do not await promises, cancel timers, or abort network requests automatically.
- Any async work started in the effect (fetch, timers, promises) continues independently.
- Signal writes inside async callbacks after disposal are no-ops (ignored by reactivity).
Required Manual Patterns
Fetch Abortion
createEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(data => setSignal(data));
onCleanup(() => controller.abort());
});
Timer Cleanup
createEffect(() => {
const id = setInterval(() => doWork(), 1000);
onCleanup(() => clearInterval(id));
});
Promise Settlement Guard
createEffect(() => {
let disposed = false;
onCleanup(() => { disposed = true; });
asyncWork().then(result => {
if (!disposed) setSignal(result);
});
});
Version and Boundary Notes
- Behavior is consistent since Solid 1.0; no major release has added auto-await or auto-cancel.
- SolidStart SSR disposes owners after rendering; client hydration creates new owners with independent cleanups.
- Nested owners (e.g.,
createRoot inside createEffect) dispose independently, LIFO per owner.
Verification Steps
- Create a minimal component with
createEffect starting fetch (with AbortController), setTimeout, and a promise.
- Register
onCleanup to abort/clear each.
- Log disposal order and verify timer does not fire after cleanup runs.
- Inspect
packages/reactive/src/owner.ts and effect.ts in SolidJS source for disposeOwner implementation.
- Test in SolidStart SSR and client hydration modes to observe owner disposal timing.
Diagnostic Detail Needed
Are you observing signal writes from async callbacks after disposal that appear to update UI, or only console warnings? This distinguishes a disposed-owner no-op from a nested-owner lifetime issue.