Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 107 additions & 7 deletions src/routes/reference/reactive-utilities/create-root.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(
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<T>(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)