From 009740d47cc33d640ba11af4653859d4b56835f0 Mon Sep 17 00:00:00 2001 From: "Amir H. Hashemi" <87268103+amirhhashemi@users.noreply.github.com> Date: Wed, 5 Nov 2025 12:27:13 +0330 Subject: [PATCH] Improve `createRoot` reference --- .../reactive-utilities/create-root.mdx | 114 ++++++++++++++++-- 1 file changed, 107 insertions(+), 7 deletions(-) diff --git a/src/routes/reference/reactive-utilities/create-root.mdx b/src/routes/reference/reactive-utilities/create-root.mdx index 207b403fa..cd633a8ab 100644 --- a/src/routes/reference/reactive-utilities/create-root.mdx +++ b/src/routes/reference/reactive-utilities/create-root.mdx @@ -9,21 +9,121 @@ tags: - scopes - disposal - tracking -version: '1.0' +version: "1.0" description: >- Create non-tracked owner scopes in SolidJS for manual memory management. Essential for nested tracking scopes and preventing auto-disposal. --- +The `createRoot` function creates a new owned context, which requires explicit disposal of computations it owns. + +## Import + +```ts +import { createRoot } from "solid-js"; +``` + +## Type + +```ts +function createRoot( + fn: (dispose: () => void) => T, + detachedOwner?: Owner +): T; +``` + +## Parameters + +### `fn` + +- **Type:** `(dispose: () => void) => T` +- **Required:** Yes + +The function executes within a newly created owned context. +The computations created within this function are managed by the root and will only be disposed of when the provided `dispose` function is called. + +If a function is passed without a `dispose` parameter, an unowned root is created. +In this case, the computations are not managed for disposal, which may lead to memory leaks. + +This function itself does not track dependencies and only runs once. + +### `detachedOwner` + +- **Type:** `Owner` +- **Required:** No + +An optional owner that establishes the root's position in the ownership hierarchy. +When provided, the root becomes owned by this owner and inherits its contextual state (such as [contexts](/concepts/context)). + +## Return Value + +`createRoot` returns the value returned by the `fn` function. + +## Examples + +### Basic Usage + +```ts +import { createSignal, createEffect, createRoot } from "solid-js"; + +function createCounter(initial = 0) { + const [count, setCount] = createSignal(initial); + + createEffect(() => { + console.log(`Count changed, new value: ${count()}`); + }); + + function increment() { + setCount((c) => c + 1); + } + + function reset() { + setCount(initial); + } + + return { count, increment, reset }; +} + +test("createCounter works correctly", () => { + createRoot((dispose) => { + const { count, increment, reset } = createCounter(10); + + expect(count()).toBe(10); + increment(); + expect(count()).toBe(11); + reset(); + expect(count()).toBe(10); + + dispose(); + }); +}); +``` + +### Returning Values + ```ts -import { createRoot } from "solid-js" +import { createRoot, createSignal, onCleanup } from "solid-js"; + +const counter = createRoot((dispose) => { + const [count, setCount] = createSignal(0); + + onCleanup(() => { + console.log("Dispose was called!"); + }); -function createRoot(fn: (dispose: () => void) => T): T + return { + value: count, + increment: () => setCount((c) => c + 1), + dispose, + }; +}); +console.log(counter.value()); // 0 +counter.increment(); +console.log(counter.value()); // 1 +counter.dispose(); // Logs "Dispose was called!" ``` -Creates a new non-tracked owner scope that doesn't auto-dispose. -This is useful for nested tracking scopes that you do not wish to release when the parent re-evaluates. +## Related -All Solid code should be wrapped in one of these top level as they ensure that all memory/computations are freed up. -Normally you do not need to worry about this as createRoot is embedded into all render entry functions. +- [`render`](/reference/rendering/render)