From 993b43d0303389c3fb96703ddc8553b1c2e0a4fd Mon Sep 17 00:00:00 2001 From: LadyBluenotes Date: Wed, 20 Aug 2025 12:01:52 -0700 Subject: [PATCH 1/8] createSignal --- .../basic-reactivity/create-signal.mdx | 313 ++++++++++++------ 1 file changed, 206 insertions(+), 107 deletions(-) diff --git a/src/routes/reference/basic-reactivity/create-signal.mdx b/src/routes/reference/basic-reactivity/create-signal.mdx index f6de896ac..1b2f91fa6 100644 --- a/src/routes/reference/basic-reactivity/create-signal.mdx +++ b/src/routes/reference/basic-reactivity/create-signal.mdx @@ -15,147 +15,246 @@ description: >- values that change over time and automatically update your UI when they do. --- -Signals are the most basic reactive primitive. -They track a single value (which can be a value of any type) that changes over time. - -```tsx -import { createSignal } from "solid-js" - -function createSignal( - initialValue: T, - options?: { - equals?: false | ((prev: T, next: T) => boolean) - name?: string - internal?: boolean - } -): [get: () => T, set: (v: T) => T] - -// available types for return value of createSignal: -import type { Signal, Accessor, Setter } from "solid-js" +Creates a reactive state primitive consisting of a getter (accessor) and a setter function that forms the foundation of Solid's reactivity system. + +## Import + +```typescript +import { createSignal } from "solid-js"; +``` + +## Type Signature + +```typescript +function createSignal(): Signal +function createSignal(value: T, options?: SignalOptions): Signal +``` + +### Related Types + +```typescript type Signal = [get: Accessor, set: Setter] + type Accessor = () => T -type Setter = (v: T | ((prev?: T) => T)) => T +type Setter = { + (value: Exclude | ((prev: T) => U)): U; + (value: (prev: T) => U): U; + (value: Exclude): U; + (value: Exclude | ((prev: T) => U)): U; +} + +interface SignalOptions { + name?: string; + equals?: false | ((prev: T, next: T) => boolean); + internal?: boolean; +} ``` -The Signal's value starts out equal to the passed first argument `initialValue` (or undefined if there are no arguments). -The `createSignal` function returns a pair of functions as a two-element array: a getter (or accessor) and a setter. -In typical use, you would destructure this array into a named Signal like so: +## Parameters -```tsx -const [count, setCount] = createSignal(0) -const [ready, setReady] = createSignal(false) -``` +### `value` + +**Type:** `T` (optional) + +The initial value for the signal. If no initial value is provided, the signal's type is automatically extended with `undefined`. + +### `options` + +**Type:** `SignalOptions` (optional) + +Configuration object for the signal. -Calling the getter (e.g., `count()` or `ready()`) returns the current value of the Signal. +#### `name` -Crucial to automatic dependency tracking, calling the getter within a tracking scope causes the calling function to depend on this Signal, so that function will rerun if the Signal gets updated. +**Type:** `string` (optional) -Calling the setter (e.g., `setCount(nextCount)` or `setReady(nextReady)`) sets the Signal's value and updates the Signal (triggering dependents to rerun) if the value actually changed (see details below). -The setter takes either the new value for the signal or a function that maps the previous value of the signal to a new value as its only argument. -The updated value is also returned by the setter. As an example: +A name for the signal used for debugging purposes in development mode. -```tsx -// read signal's current value, and -// depend on signal if in a tracking scope -// (but nonreactive outside of a tracking scope): -const currentCount = count() +#### `equals` -// or wrap any computation with a function, -// and this function can be used in a tracking scope: -const doubledCount = () => 2 * count() +**Type:** `false | ((prev: T, next: T) => boolean)` (optional) -// or build a tracking scope and depend on signal: -const countDisplay =
{count()}
+A custom comparison function to determine when the signal should update. +If set to `false`, the signal will always update regardless of value equality. By default, signals use reference equality (`===`). -// write signal by providing a value: -setReady(true) +#### `internal` -// write signal by providing a function setter: -const newCount = setCount((prev) => prev + 1) +**Type:** `boolean` (optional) +Marks the signal as internal, preventing it from appearing in development tools. +This is primarily used by Solid's internal systems. + +## Return Value + +**Type:** `Signal` + +Returns a tuple `[getter, setter]` where: + +- **getter**: An accessor function that returns the current value and tracks dependencies when called within a reactive context +- **setter**: A function that updates the signal's value and notifies all dependent computations + +## Basic Usage + +### Creating a signal with an initial value + +```typescript +const [count, setCount] = createSignal(0); + +console.log(count()); // 0 +setCount(5); +console.log(count()); // 5 ``` -:::note - If you want to store a function in a Signal you must use the function form: +### Creating a signal without an initial value + +```typescript +const [name, setName] = createSignal(); - ```tsx - setValue(() => myFunction); - ``` +console.log(name()); // undefined +setName("John"); +console.log(name()); // "John" +``` - However, functions are not treated specially as the `initialValue` argument to `createSignal`, so you can pass a - function initial value as is: +### Functional updates - ```tsx - const [func, setFunc] = createSignal(myFunction); - ``` +```typescript +const [count, setCount] = createSignal(0); -::: +setCount(prev => prev + 1); +console.log(count()); // 1 -## Options +setCount(c => c * 2); +console.log(count()); // 2 +``` -| Name | Type | Default | Description | -| ---------- | ------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `equals` | `false \| ((prev: T, next: T) => boolean)` | `===` | A function that determines whether the Signal's value has changed. If the function returns true, the Signal's value will not be updated and dependents will not rerun. If the function returns false, the Signal's value will be updated and dependents will rerun. | -| `name` | `string` | | A name for the Signal. This is useful for debugging. | -| `internal` | `boolean` | `false` | If true, the Signal will not be accessible in the devtools. | +## Advanced Usage -### `equals` +### Using a custom equality function -The `equals` option can be used to customize the equality check used to determine whether the Signal's value has changed. -By default, the equality check is a strict equality check (`===`). -If you want to use a different equality check, you can pass a custom function as the `equals` option. -The custom function will be called with the previous and next values of the Signal as arguments. -If the function returns true, the Signal's value will not be updated and dependents will not rerun. -If the function returns false, the Signal's value will be updated and dependents will rerun. +```typescript +const [user, setUser] = createSignal( + { name: "John", age: 25 }, + { + equals: (prev, next) => prev.name === next.name && prev.age === next.age + } +); -```tsx -const [count, setCount] = createSignal(0, { - equals: (prev, next) => prev === next, -}) +// This won't trigger updates because the values are considered equal +setUser({ name: "John", age: 25 }); ``` -Here are some examples of this option in use: - -```tsx -// use { equals: false } to allow modifying object in-place; -// normally this wouldn't be seen as an update because the -// object has the same identity before and after change -const [object, setObject] = createSignal({ count: 0 }, { equals: false }) -setObject((current) => { - current.count += 1 - current.updated = new Date() - return current -}) - -// use { equals: false } to create a signal that acts as a trigger without storing a value: -const [depend, rerun] = createSignal(undefined, { equals: false }) -// now calling depend() in a tracking scope -// makes that scope rerun whenever rerun() gets called - -// define equality based on string length: -const [myString, setMyString] = createSignal("string", { - equals: (newVal, oldVal) => newVal.length === oldVal.length, -}) - -setMyString("string") // considered equal to the last value and won't cause updates -setMyString("stranger") // considered different and will cause updates +### Disabling equality checking + +```typescript +const [data, setData] = createSignal([], { equals: false }); + +// This will always trigger updates, even with the same array reference +setData([]); ``` -### `name` +### Development debugging -The `name` option can be used to give the Signal a name. -This is useful for debugging. The name will be displayed in the devtools. +```typescript +const [state, setState] = createSignal( + { loading: false, data: null }, + { name: "apiState" } +); +``` -```tsx -const [count, setCount] = createSignal(0, { name: "count" }) +## Common Patterns + +### Boolean toggle + +```typescript +const [isOpen, setIsOpen] = createSignal(false); +const toggle = () => setIsOpen(prev => !prev); +``` + +### Object updates + +```typescript +const [user, setUser] = createSignal({ name: "John", age: 25 }); + +// Update specific property +const updateName = (newName: string) => + setUser(prev => ({ ...prev, name: newName })); +``` + +## How It Works + +Signals are the foundational primitive of SolidJS's fine-grained reactivity system. +When you call the accessor function within a reactive context (like inside [`createEffect`](/reference/basic-reactivity/create-effect) or a component's JSX), it automatically establishes a dependency relationship. +Any subsequent calls to the setter will trigger updates only to the specific computations that depend on that signal. + +```typescript +const [name, setName] = createSignal("John"); + +// This effect will re-run whenever name changes +createEffect(() => { + console.log(`Hello, ${name()}!`); +}); + +setName("Jane"); // Logs: "Hello, Jane!" ``` -### `internal` +## Details + +### Reactivity System Integration + +- **Effects**: Automatically track signal reads and re-run when values change +- **Memos**: Cache computed values based on signal dependencies +- **Resources**: Use signals internally for state management +- **Stores**: Built on top of signals with additional mutation tracking -The `internal` option can be used to hide the Signal from the devtools. -This is useful for Signals that are used internally by a component and should not be exposed to the user. +### Equality Checking -```tsx -const [count, setCount] = createSignal(0, { internal: true }) +By default, signals use strict equality (`===`) to determine if a value has changed: + +- Primitive values are compared by value +- Objects and arrays are compared by reference +- Setting a signal to the same reference won't trigger updates +- Setting a signal to a new object with identical properties will trigger updates + +### Function Values + +When your signal stores a function as its value, updating it requires special care because the setter treats functions as updater functions by default. +To set a function as the actual value, wrap it in another function: + +```typescript +const [fn, setFn] = createSignal(() => "hello"); + +// ❌ This treats your function as an updater, not the new value +setFn(() => "world"); // Signal becomes "world" + +// ✅ Wrap your function to store it as the actual value +setFn(() => () => "world"); // Signal becomes () => "world" (function) ``` + +The pattern is: `setSignal(() => yourNewFunction)`. +The outer function is the updater, the inner function is your actual value. + +### Development vs Production + +**Development mode:** +- Signals track additional metadata for debugging +- The `name` option provides useful names in dev tools +- Warnings are issued for signals created outside reactive contexts + +**Production mode:** +- Debugging metadata is stripped +- Dev-only options like `name` are ignored +- No warnings are issued + +### Error Handling + +- If an equality function throws an error, it's caught and handled by Solid's error boundary system +- Setter functions are synchronous and will throw immediately if errors occur +- Reading a signal outside of a reactive context is safe but won't establish tracking + +### Performance Characteristics + +- Signals are optimized for frequent reads and infrequent writes +- The equality function is called on every setter invocation +- Custom equality functions should be fast and pure +- Avoid creating signals inside frequently-called functions \ No newline at end of file From 251aee3bf32ad0ae6d148bc8585f481e17797587 Mon Sep 17 00:00:00 2001 From: LadyBluenotes Date: Wed, 20 Aug 2025 12:09:21 -0700 Subject: [PATCH 2/8] making some paragraphs instead of point form --- .../basic-reactivity/create-signal.mdx | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/routes/reference/basic-reactivity/create-signal.mdx b/src/routes/reference/basic-reactivity/create-signal.mdx index 1b2f91fa6..27c145c36 100644 --- a/src/routes/reference/basic-reactivity/create-signal.mdx +++ b/src/routes/reference/basic-reactivity/create-signal.mdx @@ -209,12 +209,9 @@ setName("Jane"); // Logs: "Hello, Jane!" ### Equality Checking -By default, signals use strict equality (`===`) to determine if a value has changed: - -- Primitive values are compared by value -- Objects and arrays are compared by reference -- Setting a signal to the same reference won't trigger updates -- Setting a signal to a new object with identical properties will trigger updates +By default, signals use strict equality (`===`) to determine if a value has changed. +This means primitive values are compared by value, while objects and arrays are compared by reference. +Setting a signal to the same reference will not trigger updates, but setting it to a new object or array, even if it has identical properties, will trigger updates. ### Function Values @@ -236,15 +233,12 @@ The outer function is the updater, the inner function is your actual value. ### Development vs Production -**Development mode:** -- Signals track additional metadata for debugging -- The `name` option provides useful names in dev tools -- Warnings are issued for signals created outside reactive contexts +In development mode, signals track additional metadata to aid debugging. +The `name` option allows you to assign meaningful names to signals, making them easier to identify in developer tools. +Additionally, Solid issues warnings if signals are created outside of reactive contexts, helping you catch potential issues early. -**Production mode:** -- Debugging metadata is stripped -- Dev-only options like `name` are ignored -- No warnings are issued +In production mode, all debugging metadata is stripped away for optimal performance. +Dev-only options like `name` are ignored, and no warnings are issued, ensuring that your application runs as efficiently as possible. ### Error Handling From 306a54aa7191ff9c4f0d2021ea9615707bf32ca4 Mon Sep 17 00:00:00 2001 From: LadyBluenotes Date: Wed, 20 Aug 2025 17:37:10 -0700 Subject: [PATCH 3/8] createComputed --- .../secondary-primitives/create-computed.mdx | 120 +++++++++++++++--- 1 file changed, 101 insertions(+), 19 deletions(-) diff --git a/src/routes/reference/secondary-primitives/create-computed.mdx b/src/routes/reference/secondary-primitives/create-computed.mdx index 90b602693..080f3cd62 100644 --- a/src/routes/reference/secondary-primitives/create-computed.mdx +++ b/src/routes/reference/secondary-primitives/create-computed.mdx @@ -15,30 +15,112 @@ description: >- primitives and handle side effects that respond to dependencies. --- -```ts -import { createComputed } from "solid-js" +Creates a reactive computation that runs immediately before render, mainly used to synchronize or write to other reactive primitives, not for DOM side-effects. -function createComputed(fn: (v: T) => T, value?: T): void +## Import +```typescript +import { createComputed } from "solid-js"; ``` -`createComputed` creates a new computation that immediately runs the given function in a tracking scope, thus automatically tracking its dependencies, and automatically reruns the function whenever the dependencies changes. -The function gets called with an argument equal to the value returned from the function's last execution, or on the first call, equal to the optional second argument to `createComputed`. -Note that the return value of the function is not otherwise exposed; in particular, createComputed has no return value. +## Type Signature -`createComputed` is the most immediate form of reactivity in Solid, and is most useful for building other reactive primitives. -For example, some other Solid primitives are built from `createComputed`. -However, it should be used with care, as `createComputed` can easily cause more unnecessary updates than other reactive primitives. -Before using it, consider the closely related primitives [`createMemo`](/reference/basic-reactivity/create-memo) and [`createRenderEffect`](/reference/secondary-primitives/create-render-effect). +```typescript +function createComputed( + * fn: (v: Init | Next) => Next, + * value?: Init, + * options?: { name?: string } + * ): void; +``` + +## Parameters + +### `fn` + +**Type:** `(v: Init | Next) => Next` + +The computation function. + Receives the previous value (or initial value, if set) and returns a new value. + Runs reactively when dependencies change. + +### `value` + +**Type:** `Init` + +Initial value for the computation. +If provided, `fn` will never receive `undefined` as its first argument. + +### `options` + +**Type:** `{ name?: string }` (optional) + +Used in development to identify the computed effect. + +## Return Value + +**Type:** `void` + +Registers a computation in the reactive system. Does _not_ return a value. + +## Usage + +```typescript +import { createComputed } from "solid-js"; + +createComputed((prev) => { + // Compute the next value based on the previous value + return prev + 1; +}, 0); +``` + +## Advanced Usage + +### Using an Initial Value + +```typescript +import { createComputed } from "solid-js"; + +createComputed((prev) => { + // Compute the next value based on the previous value + return prev + 1; +}, 0); +``` + +### Synchronizing State + +```typescript +const [source, setSource] = createSignal("initial"); +const [copy, setCopy] = createSignal(""); + +createComputed(() => setCopy(source())); +``` + +## Common Patterns + +- Writing to other reactive primitives, such as signals or stores, based on dependencies. +- Performing computations that must happen before render, not after. +- Setting up synchronization between multiple signals without side effects. + +## How It Works + +`createComputed` defines a reactive computation that tracks any signals or memos accessed within its function. +Whenever any of those dependencies change, the computation is rescheduled to run before the next render. +It is "pure" in the sense that it is not intended to cause side effects outside of updating other reactive primitives. + +## Details + +### Development vs Production + +In development mode, passing a name in the options object can help with debugging and inspection in developer tools. +In production, the name has no effect. + +### Error Handling -Like `createMemo`, `createComputed` calls its function immediately on updates (unless you're in a [batch](/reference/reactive-utilities/batch), [effect](/reference/basic-reactivity/create-effect), or [transition](/reference/reactive-utilities/use-transition)). -However, while `createMemo` functions should be pure (not set any signals), `createComputed` functions can set signals. -Related, `createMemo` offers a readonly signal for the return value of the function, whereas to do the same with `createComputed` you would need to set a signal within the function. -If it is possible to use pure functions and `createMemo`, this is likely more efficient, as Solid optimizes the execution order of memo updates, whereas updating a signal within `createComputed` will immediately trigger reactive updates some of which may turn out to be unnecessary. +- Errors thrown from the computation function are caught and reported using Solid's error boundaries or global error handlers. +- Computations created outside a root (e.g. outside `createRoot` or a component) will never be disposed, and a warning is shown in development. -## Arguments +### Performance Characteristics -| Name | Type | Description | -| :------ | :------------ | :----------------------------------------- | -| `fn` | `(v: T) => T` | The function to run in a tracking scope. | -| `value` | `T` | The initial value to pass to the function. | +- Computed functions are optimized to run only when their tracked dependencies change. +- Avoid doing expensive work or side effects in createComputed; use for reactive synchronization. +- For memoized derived values, use createMemo. For post-render side effects (e.g., DOM or network), use createEffect. From 6579274468d5dabb86b301b4e4c06f7e30eb3afe Mon Sep 17 00:00:00 2001 From: LadyBluenotes Date: Wed, 20 Aug 2025 19:24:00 -0700 Subject: [PATCH 4/8] createResource --- .../basic-reactivity/create-resource.mdx | 428 +++++++++++------- .../basic-reactivity/create-signal.mdx | 19 +- 2 files changed, 273 insertions(+), 174 deletions(-) diff --git a/src/routes/reference/basic-reactivity/create-resource.mdx b/src/routes/reference/basic-reactivity/create-resource.mdx index 2ebcfb4de..2a7468e88 100644 --- a/src/routes/reference/basic-reactivity/create-resource.mdx +++ b/src/routes/reference/basic-reactivity/create-resource.mdx @@ -17,206 +17,300 @@ description: >- integrates with Suspense for seamless data fetching in Solid.js applications. --- -`createResource` takes an asynchronous fetcher function and returns a signal that is updated with the resulting data when the fetcher completes. +Creates a reactive resource that manages asynchronous data fetching and loading states, automatically tracking dependencies and providing a simple interface for reading, refreshing, and error handling. -There are two ways to use `createResource`: you can pass the fetcher function as the sole argument, or you can additionally pass a source signal as the first argument. -The source signal will retrigger the fetcher whenever it changes, and its value will be passed to the fetcher. +## Import -```tsx -const [data, { mutate, refetch }] = createResource(fetchData) +```typescript +import { createResource } from "solid-js"; ``` -```tsx -const [data, { mutate, refetch }] = createResource(source, fetchData) +## Type Signature + +```typescript +// Without source +function createResource( + fetcher: ResourceFetcher, + options?: ResourceOptions +): ResourceReturn + +// With source +function createResource( + source: ResourceSource, + fetcher: ResourceFetcher, + options?: ResourceOptions +): ResourceReturn ``` -In these snippets, the fetcher is the function `fetchData`, and `data()` is undefined until `fetchData` finishes resolving. -In the first case, `fetchData` will be called immediately. -In the second, `fetchData` will be called as soon as `source` has any value other than false, null, or undefined. -It will be called again whenever the value of `source` changes, and that value will always be passed to `fetchData` as its first argument. - -You can call `mutate` to directly update the `data` signal (it works like any other signal setter). -You can also call refetch to rerun the fetcher directly, and pass an optional argument to provide additional info to the fetcher e.g `refetch(info)`. - -`data` works like a normal signal getter: use `data()` to read the last returned value of `fetchData`. -But it also has extra reactive properties: - -- `data.loading`: whether the fetcher has been called but not returned. -- `data.error`: if the request has errored out. - `createResource`: provides an `Error` object for `data.error`. It will show even if the fetcher throws something else. - - - Fetcher throws an `Error` instance, `data.error` will be that instance. - - If the fetcher throws a string, `data.error.message` will contain that string. - - When the fetcher throws a value that is neither an `Error` nor a string, that value will be available as `data.error.cause`. - -- As of **v1.4.0**, `data.latest` returns the last value received and will not trigger [Suspense](/reference/components/suspense) or [transitions](#TODO); if no value has been returned yet, `data.latest` will act the same as `data()`. - This can be useful if you want to show the out-of-date data while the new data is loading. - -`loading`, `error`, and `latest` are reactive getters and can be tracked. - -## The fetcher - -The `fetcher` is the async function that you provide to `createResource` to actually fetch the data. -It is passed two arguments: the value of the source signal (if provided), and an info object with two properties: `value` and `refetching`. -The `value` property tells you the previously fetched value. -The `refetching` property is true if the `fetcher` was triggered using the refetch function and false otherwise. -If the `refetch` function was called with an argument (`refetch(info)`), refetching is set to that argument. - -```tsx -async function fetchData(source, { value, refetching }) { - // Fetch the data and return a value. - //`source` tells you the current value of the source signal; - //`value` tells you the last returned value of the fetcher; - //`refetching` is true when the fetcher is triggered by calling `refetch()`, - // or equal to the optional data passed: `refetch(info)` +### Related Types + +```typescript +type ResourceReturn = [Resource, ResourceActions] + +type Resource = { + (): T | undefined + state: "unresolved" | "pending" | "ready" | "refreshing" | "errored" + loading: boolean + error: any + latest: T | undefined } -const [data, { mutate, refetch }] = createResource(getQuery, fetchData) +type ResourceActions = { + mutate: (value: T | undefined) => T | undefined + refetch: (info?: R) => Promise | T | undefined +} + +type ResourceSource = S | false | null | undefined | (() => S | false | null | undefined) + +type ResourceFetcher = ( + source: S, + info: { value: T | undefined; refetching: R | boolean } +) => T | Promise + +interface ResourceOptions { + initialValue?: T + name?: string + deferStream?: boolean + ssrLoadFrom?: "initial" | "server" + storage?: (init: T | undefined) => [Accessor, Setter] + onHydrated?: (k: S | undefined, info: { value: T | undefined }) => void +} +``` + +## Parameters + +### `source` +- **Type:** `ResourceSource` +- **Default:** `undefined` + +Reactive data source whose non-nullish and non-false values are passed to the fetcher. +When the source changes, the fetcher is automatically re-run. + +### `fetcher` +- **Type:** `ResourceFetcher` + +Function that receives the source value (or `true` if no source), the current resource info, and returns a value or Promise. + +### `options` +- **Type:** `ResourceOptions` +- **Default:** `{}` + +Configuration options for the resource. + +## Options + +### `initialValue` +- **Type:** `T` +- **Default:** `undefined` + +Initial value for the resource. +When provided, the resource starts in "ready" state and the type excludes `undefined`. + +### `name` +- **Type:** `string` +- **Default:** `undefined` + +A name for debugging purposes in development mode. + +### `deferStream` +- **Type:** `boolean` +- **Default:** `false` + +Controls streaming behavior during server-side rendering. + +### `ssrLoadFrom` +- **Type:** `"initial" | "server"` +- **Default:** `"server"` + +Determines how the resource loads during SSR hydration. + +### `storage` +- **Type:** `(init: T | undefined) => [Accessor, Setter]` +- **Default:** `createSignal` -// read value -data() +Custom storage function for the resource value, useful for persistence or custom state management. -// check if loading -data.loading +### `onHydrated` +- **Type:** `(k: S | undefined, info: { value: T | undefined }) => void` +- **Default:** `undefined` -// check if errored -data.error +Callback fired when the resource hydrates on the client side. -// directly set value without creating promise -mutate(optimisticValue) +## Return Value -// refetch the last request explicitly -refetch() +- **Type:** `[Resource, ResourceActions]` +Returns a tuple containing the resource accessor and resource actions. + +### `Resource` + +```typescript +type Resource = { + (): T | undefined + state: "unresolved" | "pending" | "ready" | "refreshing" | "errored" + loading: boolean + error: any + latest: T | undefined +} ``` -## Version 1.4.0 and Later +- `state`: Current state of the resource. +- `loading`: Indicates if the resource is currently loading. +- `error`: Error information if the resource failed to load. +- `latest`: The latest value of the resource. + + +### `ResourceActions` + +```typescript +type ResourceActions = { + mutate: (value: T | undefined) => T | undefined + refetch: (info?: R) => Promise | T | undefined +} +``` -#### v1.4.0 +- `mutate`: Function to Manually overwrite the resource value without calling the fetcher. +- `refetch`: Function to re-run the fetcher without changing the source. +If a parameter is provided to `refetch`, it will be passed to the fetcher's `refetching` property. -If you're using `renderToStream`, you can tell Solid to wait for a resource before flushing the stream using the `deferStream` option: +## Usage -```tsx -// fetches a user and streams content as soon as possible -const [user] = createResource(() => params.id, fetchUser) +### Basic Usage -// fetches a user but only streams content after this resource has loaded -const [user] = createResource(() => params.id, fetchUser, { - deferStream: true, -}) +```typescript +Basic Usage + +const [data] = createResource(async () => { + const response = await fetch('/api/data'); + return response.json(); +}); + +// Access data +console.log(data()); // undefined initially, then fetched data +console.log(data.loading); // true during fetch +console.log(data.state); // "pending" → "ready" ``` -#### v1.5.0 +### With Source + +```typescript +const [userId, setUserId] = createSignal(1); -1. We've added a new state field which covers a more detailed view of the Resource state beyond `loading` and `error`. -You can now check whether a Resource is `unresolved`, `pending`, `ready`, `refreshing`, or `errored`. +const [user] = createResource(userId, async (id) => { + const response = await fetch(`/api/users/${id}`); + return response.json(); +}); + +// Automatically refetches when userId changes +setUserId(2); +``` -| State | Value resolved | Loading | Has error | -| ------------ | -------------- | ------- | --------- | -| `unresolved` | No | No | No | -| `pending` | No | Yes | No | -| `ready` | Yes | No | No | -| `refreshing` | Yes | Yes | No | -| `errored` | No | No | Yes | +### With Actions -2. When server-rendering resources, especially when embedding Solid in other systems that fetch data before rendering, you might want to initialize the resource with this prefetched value instead of fetching again and having the resource serialize it in its own state. -You can use the new `ssrLoadFrom` option for this. -Instead of using the default `server` value, you can pass `initial` and the resource will use `initialValue` as if it were the result of the first fetch for both SSR and hydration. +```typescript +const [posts, { refetch, mutate }] = createResource(fetchPosts); -```tsx -const [data, { mutate, refetch }] = createResource(() => params.id, fetchUser, { - initialValue: preloadedData, - ssrLoadFrom: "initial", -}) +// Manual refetch +await refetch(); + +// Optimistic update +mutate(posts => [...posts, newPost]); ``` -3. Resources can be set with custom defined storage with the same signature as a Signal by using the storage option. -For example using a custom reconciling store could be done this way: - -```tsx -function createDeepSignal(value: T): Signal { - const [store, setStore] = createStore({ - value, - }) - return [ - () => store.value, - (v: T) => { - const unwrapped = unwrap(store.value) - typeof v === "function" && (v = v(unwrapped)) - setStore("value", reconcile(v)) - return store.value - }, - ] as Signal -} +### Error handling -const [resource] = createResource(fetcher, { - storage: createDeepSignal, -}) +```typescript +const [data] = createResource(async () => { + const response = await fetch('/api/data'); + if (!response.ok) throw new Error('Failed to fetch'); + return response.json(); +}); + +// In JSX +Error loading data}> +
{data()?.title}
+
``` -This option is still experimental and may change in the future. +### With Initial Value -## Options +```typescript +const [user] = createResource( + () => fetchUser(), + { initialValue: { name: 'Loading...', id: 0 } } +); -The `createResource` function takes an optional third argument, an options object. The options are: - -| Name | Type | Default | Description | -| ------------ | ----------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| name | `string` | `undefined` | A name for the resource. This is used for debugging purposes. | -| deferStream | `boolean` | `false` | If true, Solid will wait for the resource to resolve before flushing the stream. | -| initialValue | `any` | `undefined` | The initial value of the resource. | -| onHydrated | `function` | `undefined` | A callback that is called when the resource is hydrated. | -| ssrLoadFrom | `"server" \| "initial"` | `"server"` | The source of the initial value for SSR. If set to `"initial"`, the resource will use the `initialValue` option instead of the value returned by the fetcher. | -| storage | `function` | `createSignal` | A function that returns a signal. This can be used to create a custom storage for the resource. This is still experimental | - -## Note for TypeScript users - -The function and type definitions for `createResource` are as follows: - -```tsx -import { createResource } from "solid-js" -import type { ResourceReturn, ResourceOptions } from "solid-js" - -type ResourceReturn = [ - { - (): T | undefined - state: "unresolved" | "pending" | "ready" | "refreshing" | "errored" - loading: boolean - error: any - latest: T | undefined - }, - { - mutate: (v: T | undefined) => T | undefined - refetch: (info: unknown) => Promise | T - } -] - -type ResourceOptions = { - initialValue?: T - name?: string - deferStream?: boolean - ssrLoadFrom?: "initial" | "server" - storage?: ( - init: T | undefined - ) => [Accessor, Setter] - onHydrated?: (k: S | undefined, info: { value: T | undefined }) => void -} +// user() is never undefined +console.log(user().name); // "Loading..." initially +``` -function createResource( - fetcher: ( - k: U, - info: { value: T | undefined; refetching: boolean | unknown } - ) => T | Promise, - options?: ResourceOptions -): ResourceReturn - -function createResource( - source: U | false | null | (() => U | false | null), - fetcher: ( - k: U, - info: { value: T | undefined; refetching: boolean | unknown } - ) => T | Promise, - options?: ResourceOptions -): ResourceReturn +### Conditional Fetching +```typescript +const [isEnabled, setIsEnabled] = createSignal(false); + +const [data] = createResource( + () => isEnabled() && userId(), // Only fetches when enabled and userId exists + async (id) => fetchUserData(id) +); ``` + +## Details + +Resources provide a reactive pattern for handling asynchronous data that integrates seamlessly with SolidJS's reactivity system and Suspense boundaries. +Unlike signals, resources are specifically designed for async operations and provide built-in loading states, error handling, and refetching capabilities. + +### State Management + +State follows a predictable lifecycle: `"unresolved" → "pending" → "ready"/"errored"`. +During refetching, the state transitions to `"refreshing"` while maintaining the previous value accessible via the latest property. +This prevents UI flickering during updates. + +In version v.1.5.0, resources gained the ability to cover a more detailed view of the Resource state, beyond `loading` and `error` states. +This includes distinct states for initial loading, successful fetches, refetching, and errors: + +| State | Description | Loading | Error | Latest | +| ------ | ----------- | ------- | ----- | ------ | +| `unresolved` | Initial state, not yet fetched | `false` | `undefined` | `undefined` | +| `pending` | Fetching in progress | `true` | `undefined` | `undefined` | +| `ready` | Successfully fetched | `false` | `undefined` | `T` | +| `refreshing` | Refetching while keeping previous value | `true` | `undefined` | `T` | +| `errored` | Fetching failed | `false` | `any` | `undefined` | + +### Source Reactivity + +Source automatically triggers refetching when the source value changes. +The fetcher only runs when the source is truthy (not `null`, `undefined`, or `false`), allowing for conditional fetching patterns. +Sources can be static values, reactive accessors, or computed values. + +### Refetching Behavior + +Refetching lets you manually trigger the fetcher using the `refetch` action, optionally passing extra parameters for more control over the request. +The `mutate` action allows you to optimistically update the resource value locally, without making a network request. + +### Suspense Integration + +Resources automatically suspend the nearest `` boundary while loading, allowing you to declaratively show fallback UI until data is ready. +When a resource is pending or refreshing, components reading its value will suspend, and the fallback of the closest Suspense boundary will be displayed. +If an error is thrown, the nearest `` will catch it. + +### SSR and Hydration + +Solid's resources are designed for seamless server-side rendering (SSR) and hydration. +During SSR, resource data is serialized and streamed to the client, enabling fast initial page loads and smooth transitions. +The `ssrLoadFrom` option lets you control how the resource behaves after hydration: + +- `"server"` (default): The client uses the value fetched on the server during hydration, providing immediate access to data without additional fetches. +- `"initial"`: The client re-fetches the data after hydration, allowing for dynamic updates but potentially leading to a loading state on the client. + +### Error Handling + +- Resources provide built-in error handling capabilities, allowing you to easily manage errors that occur during data fetching. +- Accessing the resource value when in error state re-throws the error, triggering error boundaries. The `ErrorBoundary` component can be used to catch errors and display fallback UI. + +### Performance Characteristics + +Performance is enhanced by automatically deduplicating concurrent fetches and leveraging Solid's fine-grained reactivity and batching mechanisms. +During server-side rendering, resources can stream data for faster initial loads and improved user experience. + + diff --git a/src/routes/reference/basic-reactivity/create-signal.mdx b/src/routes/reference/basic-reactivity/create-signal.mdx index 27c145c36..2980e7e21 100644 --- a/src/routes/reference/basic-reactivity/create-signal.mdx +++ b/src/routes/reference/basic-reactivity/create-signal.mdx @@ -55,46 +55,51 @@ interface SignalOptions { ### `value` -**Type:** `T` (optional) +- **Type:** `T` +- **Default:** `undefined` The initial value for the signal. If no initial value is provided, the signal's type is automatically extended with `undefined`. ### `options` -**Type:** `SignalOptions` (optional) +- **Type:** `SignalOptions` +- **Default:** `undefined` Configuration object for the signal. #### `name` -**Type:** `string` (optional) +- **Type:** `string` +- **Default:** `undefined` A name for the signal used for debugging purposes in development mode. #### `equals` -**Type:** `false | ((prev: T, next: T) => boolean)` (optional) +- **Type:** `false | ((prev: T, next: T) => boolean)` +- **Default:** `false` A custom comparison function to determine when the signal should update. If set to `false`, the signal will always update regardless of value equality. By default, signals use reference equality (`===`). #### `internal` -**Type:** `boolean` (optional) +- **Type:** `boolean` +- **Default:** `false` Marks the signal as internal, preventing it from appearing in development tools. This is primarily used by Solid's internal systems. ## Return Value -**Type:** `Signal` +- **Type:** `Signal` Returns a tuple `[getter, setter]` where: - **getter**: An accessor function that returns the current value and tracks dependencies when called within a reactive context - **setter**: A function that updates the signal's value and notifies all dependent computations -## Basic Usage +## Usage ### Creating a signal with an initial value From 86e2e3e453d2ffac0d5619d1e868798ca4e6a32b Mon Sep 17 00:00:00 2001 From: LadyBluenotes Date: Thu, 27 Nov 2025 09:49:03 -0800 Subject: [PATCH 5/8] remove usage examples --- .../basic-reactivity/create-signal.mdx | 85 ------------------- 1 file changed, 85 deletions(-) diff --git a/src/routes/reference/basic-reactivity/create-signal.mdx b/src/routes/reference/basic-reactivity/create-signal.mdx index 2980e7e21..fe2794759 100644 --- a/src/routes/reference/basic-reactivity/create-signal.mdx +++ b/src/routes/reference/basic-reactivity/create-signal.mdx @@ -101,91 +101,6 @@ Returns a tuple `[getter, setter]` where: ## Usage -### Creating a signal with an initial value - -```typescript -const [count, setCount] = createSignal(0); - -console.log(count()); // 0 -setCount(5); -console.log(count()); // 5 -``` - -### Creating a signal without an initial value - -```typescript -const [name, setName] = createSignal(); - -console.log(name()); // undefined -setName("John"); -console.log(name()); // "John" -``` - -### Functional updates - -```typescript -const [count, setCount] = createSignal(0); - -setCount(prev => prev + 1); -console.log(count()); // 1 - -setCount(c => c * 2); -console.log(count()); // 2 -``` - -## Advanced Usage - -### Using a custom equality function - -```typescript -const [user, setUser] = createSignal( - { name: "John", age: 25 }, - { - equals: (prev, next) => prev.name === next.name && prev.age === next.age - } -); - -// This won't trigger updates because the values are considered equal -setUser({ name: "John", age: 25 }); -``` - -### Disabling equality checking - -```typescript -const [data, setData] = createSignal([], { equals: false }); - -// This will always trigger updates, even with the same array reference -setData([]); -``` - -### Development debugging - -```typescript -const [state, setState] = createSignal( - { loading: false, data: null }, - { name: "apiState" } -); -``` - -## Common Patterns - -### Boolean toggle - -```typescript -const [isOpen, setIsOpen] = createSignal(false); -const toggle = () => setIsOpen(prev => !prev); -``` - -### Object updates - -```typescript -const [user, setUser] = createSignal({ name: "John", age: 25 }); - -// Update specific property -const updateName = (newName: string) => - setUser(prev => ({ ...prev, name: newName })); -``` - ## How It Works Signals are the foundational primitive of SolidJS's fine-grained reactivity system. From c37829fc1c5659ba2413790a1e9596d1cf6b0114 Mon Sep 17 00:00:00 2001 From: LadyBluenotes Date: Mon, 1 Dec 2025 12:34:09 -0800 Subject: [PATCH 6/8] examples section --- .../basic-reactivity/create-signal.mdx | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/routes/reference/basic-reactivity/create-signal.mdx b/src/routes/reference/basic-reactivity/create-signal.mdx index fe2794759..b56ff12d0 100644 --- a/src/routes/reference/basic-reactivity/create-signal.mdx +++ b/src/routes/reference/basic-reactivity/create-signal.mdx @@ -99,7 +99,25 @@ Returns a tuple `[getter, setter]` where: - **getter**: An accessor function that returns the current value and tracks dependencies when called within a reactive context - **setter**: A function that updates the signal's value and notifies all dependent computations -## Usage +## Examples + +### Basic Usage + +```tsx +import { createSignal } from "solid-js"; + +function Counter() { + const [count, setCount] = createSignal(0); + + return ( +
+ + {count()} +
+ ); +} + +``` ## How It Works From 077cfcdb3301372c5ac12ed7d95d818debb289cd Mon Sep 17 00:00:00 2001 From: Sarah Gerrard <98355961+LadyBluenotes@users.noreply.github.com> Date: Tue, 2 Dec 2025 17:27:09 +0000 Subject: [PATCH 7/8] update createResource page, revert changes in createComputed, and update createSignal page. --- .../basic-reactivity/create-resource.mdx | 98 +++-------- .../basic-reactivity/create-signal.mdx | 85 ++-------- .../secondary-primitives/create-computed.mdx | 152 +++++++++--------- 3 files changed, 111 insertions(+), 224 deletions(-) diff --git a/src/routes/reference/basic-reactivity/create-resource.mdx b/src/routes/reference/basic-reactivity/create-resource.mdx index 2a7468e88..c82198cfc 100644 --- a/src/routes/reference/basic-reactivity/create-resource.mdx +++ b/src/routes/reference/basic-reactivity/create-resource.mdx @@ -18,6 +18,7 @@ description: >- --- Creates a reactive resource that manages asynchronous data fetching and loading states, automatically tracking dependencies and providing a simple interface for reading, refreshing, and error handling. +It integrates with Solid's reactivity system and Suspense boundaries. ## Import @@ -25,7 +26,7 @@ Creates a reactive resource that manages asynchronous data fetching and loading import { createResource } from "solid-js"; ``` -## Type Signature +## Type ```typescript // Without source @@ -42,7 +43,7 @@ function createResource( ): ResourceReturn ``` -### Related Types +### Related types ```typescript type ResourceReturn = [Resource, ResourceActions] @@ -97,40 +98,41 @@ Function that receives the source value (or `true` if no source), the current re Configuration options for the resource. -## Options - -### `initialValue` +#### `initialValue` - **Type:** `T` - **Default:** `undefined` Initial value for the resource. When provided, the resource starts in "ready" state and the type excludes `undefined`. -### `name` +#### `name` - **Type:** `string` - **Default:** `undefined` A name for debugging purposes in development mode. -### `deferStream` +#### `deferStream` - **Type:** `boolean` - **Default:** `false` Controls streaming behavior during server-side rendering. -### `ssrLoadFrom` +#### `ssrLoadFrom` - **Type:** `"initial" | "server"` - **Default:** `"server"` Determines how the resource loads during SSR hydration. -### `storage` +- "server": Uses the server-fetched value during hydration. +- "initial": Re-fetches on the client after hydration. + +#### `storage` - **Type:** `(init: T | undefined) => [Accessor, Setter]` - **Default:** `createSignal` Custom storage function for the resource value, useful for persistence or custom state management. -### `onHydrated` +#### `onHydrated` - **Type:** `(k: S | undefined, info: { value: T | undefined }) => void` - **Default:** `undefined` @@ -155,10 +157,19 @@ type Resource = { ``` - `state`: Current state of the resource. +See table below for state descriptions. - `loading`: Indicates if the resource is currently loading. - `error`: Error information if the resource failed to load. - `latest`: The latest value of the resource. +| State | Description | Loading | Error | Latest | +| ------ | ----------- | ------- | ----- | ------ | +| `unresolved` | Initial state, not yet fetched | `false` | `undefined` | `undefined` | +| `pending` | Fetching in progress | `true` | `undefined` | `undefined` | +| `ready` | Successfully fetched | `false` | `undefined` | `T` | +| `refreshing` | Refetching while keeping previous value | `true` | `undefined` | `T` | +| `errored` | Fetching failed | `false` | `any` | `undefined` | + ### `ResourceActions` @@ -170,16 +181,15 @@ type ResourceActions = { ``` - `mutate`: Function to Manually overwrite the resource value without calling the fetcher. +Allows you to optimistically update the resource value locally, without making a network request. - `refetch`: Function to re-run the fetcher without changing the source. If a parameter is provided to `refetch`, it will be passed to the fetcher's `refetching` property. -## Usage +## Examples -### Basic Usage +### Basic usage ```typescript -Basic Usage - const [data] = createResource(async () => { const response = await fetch('/api/data'); return response.json(); @@ -254,63 +264,3 @@ const [data] = createResource( async (id) => fetchUserData(id) ); ``` - -## Details - -Resources provide a reactive pattern for handling asynchronous data that integrates seamlessly with SolidJS's reactivity system and Suspense boundaries. -Unlike signals, resources are specifically designed for async operations and provide built-in loading states, error handling, and refetching capabilities. - -### State Management - -State follows a predictable lifecycle: `"unresolved" → "pending" → "ready"/"errored"`. -During refetching, the state transitions to `"refreshing"` while maintaining the previous value accessible via the latest property. -This prevents UI flickering during updates. - -In version v.1.5.0, resources gained the ability to cover a more detailed view of the Resource state, beyond `loading` and `error` states. -This includes distinct states for initial loading, successful fetches, refetching, and errors: - -| State | Description | Loading | Error | Latest | -| ------ | ----------- | ------- | ----- | ------ | -| `unresolved` | Initial state, not yet fetched | `false` | `undefined` | `undefined` | -| `pending` | Fetching in progress | `true` | `undefined` | `undefined` | -| `ready` | Successfully fetched | `false` | `undefined` | `T` | -| `refreshing` | Refetching while keeping previous value | `true` | `undefined` | `T` | -| `errored` | Fetching failed | `false` | `any` | `undefined` | - -### Source Reactivity - -Source automatically triggers refetching when the source value changes. -The fetcher only runs when the source is truthy (not `null`, `undefined`, or `false`), allowing for conditional fetching patterns. -Sources can be static values, reactive accessors, or computed values. - -### Refetching Behavior - -Refetching lets you manually trigger the fetcher using the `refetch` action, optionally passing extra parameters for more control over the request. -The `mutate` action allows you to optimistically update the resource value locally, without making a network request. - -### Suspense Integration - -Resources automatically suspend the nearest `` boundary while loading, allowing you to declaratively show fallback UI until data is ready. -When a resource is pending or refreshing, components reading its value will suspend, and the fallback of the closest Suspense boundary will be displayed. -If an error is thrown, the nearest `` will catch it. - -### SSR and Hydration - -Solid's resources are designed for seamless server-side rendering (SSR) and hydration. -During SSR, resource data is serialized and streamed to the client, enabling fast initial page loads and smooth transitions. -The `ssrLoadFrom` option lets you control how the resource behaves after hydration: - -- `"server"` (default): The client uses the value fetched on the server during hydration, providing immediate access to data without additional fetches. -- `"initial"`: The client re-fetches the data after hydration, allowing for dynamic updates but potentially leading to a loading state on the client. - -### Error Handling - -- Resources provide built-in error handling capabilities, allowing you to easily manage errors that occur during data fetching. -- Accessing the resource value when in error state re-throws the error, triggering error boundaries. The `ErrorBoundary` component can be used to catch errors and display fallback UI. - -### Performance Characteristics - -Performance is enhanced by automatically deduplicating concurrent fetches and leveraging Solid's fine-grained reactivity and batching mechanisms. -During server-side rendering, resources can stream data for faster initial loads and improved user experience. - - diff --git a/src/routes/reference/basic-reactivity/create-signal.mdx b/src/routes/reference/basic-reactivity/create-signal.mdx index b56ff12d0..f59c092f3 100644 --- a/src/routes/reference/basic-reactivity/create-signal.mdx +++ b/src/routes/reference/basic-reactivity/create-signal.mdx @@ -16,6 +16,7 @@ description: >- --- Creates a reactive state primitive consisting of a getter (accessor) and a setter function that forms the foundation of Solid's reactivity system. +Signals are optimized for frequent reads and infrequent writes ## Import @@ -66,6 +67,8 @@ The initial value for the signal. If no initial value is provided, the signal's - **Default:** `undefined` Configuration object for the signal. +In production mode, all debugging metadata is stripped away for optimal performance. +Dev-only options like `name` are ignored, and no warnings are issued, ensuring that your application runs as efficiently as possible. #### `name` @@ -73,14 +76,18 @@ Configuration object for the signal. - **Default:** `undefined` A name for the signal used for debugging purposes in development mode. +The name will show up in console messages and in the [Solid devtools](https://github.com/thetarnav/solid-devtools). #### `equals` - **Type:** `false | ((prev: T, next: T) => boolean)` - **Default:** `false` +By default, signals use reference equality (`===`). A custom comparison function to determine when the signal should update. -If set to `false`, the signal will always update regardless of value equality. By default, signals use reference equality (`===`). +If set to `false`, the signal will always update regardless of value equality. +This can be useful to create a Signal that triggers manual updates in the reactive system, but must remain a pure function. + #### `internal` @@ -101,7 +108,7 @@ Returns a tuple `[getter, setter]` where: ## Examples -### Basic Usage +### Basic usage ```tsx import { createSignal } from "solid-js"; @@ -117,76 +124,4 @@ function Counter() { ); } -``` - -## How It Works - -Signals are the foundational primitive of SolidJS's fine-grained reactivity system. -When you call the accessor function within a reactive context (like inside [`createEffect`](/reference/basic-reactivity/create-effect) or a component's JSX), it automatically establishes a dependency relationship. -Any subsequent calls to the setter will trigger updates only to the specific computations that depend on that signal. - -```typescript -const [name, setName] = createSignal("John"); - -// This effect will re-run whenever name changes -createEffect(() => { - console.log(`Hello, ${name()}!`); -}); - -setName("Jane"); // Logs: "Hello, Jane!" -``` - -## Details - -### Reactivity System Integration - -- **Effects**: Automatically track signal reads and re-run when values change -- **Memos**: Cache computed values based on signal dependencies -- **Resources**: Use signals internally for state management -- **Stores**: Built on top of signals with additional mutation tracking - -### Equality Checking - -By default, signals use strict equality (`===`) to determine if a value has changed. -This means primitive values are compared by value, while objects and arrays are compared by reference. -Setting a signal to the same reference will not trigger updates, but setting it to a new object or array, even if it has identical properties, will trigger updates. - -### Function Values - -When your signal stores a function as its value, updating it requires special care because the setter treats functions as updater functions by default. -To set a function as the actual value, wrap it in another function: - -```typescript -const [fn, setFn] = createSignal(() => "hello"); - -// ❌ This treats your function as an updater, not the new value -setFn(() => "world"); // Signal becomes "world" - -// ✅ Wrap your function to store it as the actual value -setFn(() => () => "world"); // Signal becomes () => "world" (function) -``` - -The pattern is: `setSignal(() => yourNewFunction)`. -The outer function is the updater, the inner function is your actual value. - -### Development vs Production - -In development mode, signals track additional metadata to aid debugging. -The `name` option allows you to assign meaningful names to signals, making them easier to identify in developer tools. -Additionally, Solid issues warnings if signals are created outside of reactive contexts, helping you catch potential issues early. - -In production mode, all debugging metadata is stripped away for optimal performance. -Dev-only options like `name` are ignored, and no warnings are issued, ensuring that your application runs as efficiently as possible. - -### Error Handling - -- If an equality function throws an error, it's caught and handled by Solid's error boundary system -- Setter functions are synchronous and will throw immediately if errors occur -- Reading a signal outside of a reactive context is safe but won't establish tracking - -### Performance Characteristics - -- Signals are optimized for frequent reads and infrequent writes -- The equality function is called on every setter invocation -- Custom equality functions should be fast and pure -- Avoid creating signals inside frequently-called functions \ No newline at end of file +``` \ No newline at end of file diff --git a/src/routes/reference/secondary-primitives/create-computed.mdx b/src/routes/reference/secondary-primitives/create-computed.mdx index 1ae220110..7e70a5d4b 100644 --- a/src/routes/reference/secondary-primitives/create-computed.mdx +++ b/src/routes/reference/secondary-primitives/create-computed.mdx @@ -15,112 +15,114 @@ description: >- primitives and handle side effects that respond to dependencies. --- -Creates a reactive computation that runs immediately before render, mainly used to synchronize or write to other reactive primitives, not for DOM side-effects. +The `createComputed` function creates a reactive computation that runs _before_ the rendering phase. +It is primarily used to synchronize state before rendering begins. ## Import -```typescript +```ts import { createComputed } from "solid-js"; ``` -## Type Signature +## Type -```typescript +```ts +function createComputed( + fn: EffectFunction, Next> +): void; function createComputed( - * fn: (v: Init | Next) => Next, - * value?: Init, - * options?: { name?: string } - * ): void; + fn: EffectFunction, + value: Init, + options?: { name?: string } +): void; +function createComputed( + fn: EffectFunction, + value?: Init, + options?: { name?: string } +): void; ``` ## Parameters ### `fn` -**Type:** `(v: Init | Next) => Next` +- **Type:** `EffectFunction, Next> | EffectFunction` +- **Required:** Yes -The computation function. - Receives the previous value (or initial value, if set) and returns a new value. - Runs reactively when dependencies change. +The function that performs the computation. +It executes immediately to track dependencies and re-runs whenever a dependency changes. -### `value` +It receives the value returned from the previous execution as its argument. +On the initial execution, it receives the [`value`](#value) parameter (if provided) or `undefined`. -**Type:** `Init` +### `value` -Initial value for the computation. -If provided, `fn` will never receive `undefined` as its first argument. +- **Type:** `Init` +- **Required:** No -### `options` +The initial value passed to `fn` on its first execution. -**Type:** `{ name?: string }` (optional) +### `options` -Used in development to identify the computed effect. +- **Type:** `{ name?: string }` +- **Required:** No -## Return Value +An optional configuration object with the following properties: -**Type:** `void` +#### `name` -Registers a computation in the reactive system. Does _not_ return a value. +- **Type:** `string` +- **Required:** No -## Usage +A debug name for the computation. +It is used for identification in debugging tools like the [Solid Debugger](https://github.com/thetarnav/solid-devtools). -```typescript -import { createComputed } from "solid-js"; +## Return value -createComputed((prev) => { - // Compute the next value based on the previous value - return prev + 1; -}, 0); -``` +- **Type:** `void` -## Advanced Usage +`createComputed` does not return a value. -### Using an Initial Value +## Examples -```typescript -import { createComputed } from "solid-js"; - -createComputed((prev) => { - // Compute the next value based on the previous value - return prev + 1; -}, 0); -``` +### Basic usage -### Synchronizing State - -```typescript -const [source, setSource] = createSignal("initial"); -const [copy, setCopy] = createSignal(""); - -createComputed(() => setCopy(source())); +```tsx +import { createComputed } from "solid-js"; +import { createStore } from "solid-js/store"; + +type User = { + name?: string; +}; + +type UserEditorProps = { + user: User; +}; + +function UserEditor(props: UserEditorProps) { + const [formData, setFormData] = createStore({ + name: "", + }); + + // Update the store synchronously when props change. + // This prevents a second render cycle. + createComputed(() => { + setFormData("name", props.user.name); + }); + + return ( +
+

Editing: {formData.name}

+ setFormData("name", e.currentTarget.value)} + /> +
+ ); +} ``` -## Common Patterns - -- Writing to other reactive primitives, such as signals or stores, based on dependencies. -- Performing computations that must happen before render, not after. -- Setting up synchronization between multiple signals without side effects. - -## How It Works - -`createComputed` defines a reactive computation that tracks any signals or memos accessed within its function. -Whenever any of those dependencies change, the computation is rescheduled to run before the next render. -It is "pure" in the sense that it is not intended to cause side effects outside of updating other reactive primitives. - -## Details - -### Development vs Production - -In development mode, passing a name in the options object can help with debugging and inspection in developer tools. -In production, the name has no effect. - -### Error Handling - -- Errors thrown from the computation function are caught and reported using Solid's error boundaries or global error handlers. -- Computations created outside a root (e.g. outside `createRoot` or a component) will never be disposed, and a warning is shown in development. - -### Performance Characteristics +## Related -- Computed functions are optimized to run only when their tracked dependencies change. -- Avoid doing expensive work or side effects in createComputed; use for reactive synchronization. -- For memoized derived values, use createMemo. For post-render side effects (e.g., DOM or network), use createEffect. +- [`createMemo`](/reference/basic-reactivity/create-memo) +- [`createRenderEffect`](/reference/secondary-primitives/create-render-effect) \ No newline at end of file From 66afe9b8035e236946b2fa578d0cd3f96fdd69e6 Mon Sep 17 00:00:00 2001 From: Sarah Gerrard <98355961+LadyBluenotes@users.noreply.github.com> Date: Tue, 2 Dec 2025 20:49:41 +0000 Subject: [PATCH 8/8] format --- .../basic-reactivity/create-resource.mdx | 138 ++++++++++-------- .../basic-reactivity/create-signal.mdx | 42 +++--- .../secondary-primitives/create-computed.mdx | 2 +- 3 files changed, 97 insertions(+), 85 deletions(-) diff --git a/src/routes/reference/basic-reactivity/create-resource.mdx b/src/routes/reference/basic-reactivity/create-resource.mdx index c82198cfc..fd975456e 100644 --- a/src/routes/reference/basic-reactivity/create-resource.mdx +++ b/src/routes/reference/basic-reactivity/create-resource.mdx @@ -11,7 +11,7 @@ tags: - loading - error-handling - ssr -version: '1.0' +version: "1.0" description: >- Fetch async data with createResource. Handles loading states, errors, and integrates with Suspense for seamless data fetching in Solid.js applications. @@ -31,93 +31,107 @@ import { createResource } from "solid-js"; ```typescript // Without source function createResource( - fetcher: ResourceFetcher, - options?: ResourceOptions -): ResourceReturn + fetcher: ResourceFetcher, + options?: ResourceOptions +): ResourceReturn; // With source function createResource( - source: ResourceSource, - fetcher: ResourceFetcher, - options?: ResourceOptions -): ResourceReturn + source: ResourceSource, + fetcher: ResourceFetcher, + options?: ResourceOptions +): ResourceReturn; ``` ### Related types ```typescript -type ResourceReturn = [Resource, ResourceActions] +type ResourceReturn = [Resource, ResourceActions]; type Resource = { - (): T | undefined - state: "unresolved" | "pending" | "ready" | "refreshing" | "errored" - loading: boolean - error: any - latest: T | undefined -} + (): T | undefined; + state: "unresolved" | "pending" | "ready" | "refreshing" | "errored"; + loading: boolean; + error: any; + latest: T | undefined; +}; type ResourceActions = { - mutate: (value: T | undefined) => T | undefined - refetch: (info?: R) => Promise | T | undefined -} + mutate: (value: T | undefined) => T | undefined; + refetch: (info?: R) => Promise | T | undefined; +}; -type ResourceSource = S | false | null | undefined | (() => S | false | null | undefined) +type ResourceSource = + | S + | false + | null + | undefined + | (() => S | false | null | undefined); type ResourceFetcher = ( - source: S, - info: { value: T | undefined; refetching: R | boolean } -) => T | Promise + source: S, + info: { value: T | undefined; refetching: R | boolean } +) => T | Promise; interface ResourceOptions { - initialValue?: T - name?: string - deferStream?: boolean - ssrLoadFrom?: "initial" | "server" - storage?: (init: T | undefined) => [Accessor, Setter] - onHydrated?: (k: S | undefined, info: { value: T | undefined }) => void + initialValue?: T; + name?: string; + deferStream?: boolean; + ssrLoadFrom?: "initial" | "server"; + storage?: ( + init: T | undefined + ) => [Accessor, Setter]; + onHydrated?: (k: S | undefined, info: { value: T | undefined }) => void; } ``` ## Parameters ### `source` + - **Type:** `ResourceSource` - **Default:** `undefined` -Reactive data source whose non-nullish and non-false values are passed to the fetcher. +Reactive data source whose non-nullish and non-false values are passed to the fetcher. When the source changes, the fetcher is automatically re-run. ### `fetcher` + - **Type:** `ResourceFetcher` Function that receives the source value (or `true` if no source), the current resource info, and returns a value or Promise. ### `options` + - **Type:** `ResourceOptions` - **Default:** `{}` Configuration options for the resource. #### `initialValue` + - **Type:** `T` - **Default:** `undefined` -Initial value for the resource. +Initial value for the resource. When provided, the resource starts in "ready" state and the type excludes `undefined`. #### `name` + - **Type:** `string` - **Default:** `undefined` A name for debugging purposes in development mode. #### `deferStream` + - **Type:** `boolean` - **Default:** `false` Controls streaming behavior during server-side rendering. #### `ssrLoadFrom` + - **Type:** `"initial" | "server"` - **Default:** `"server"` @@ -127,12 +141,14 @@ Determines how the resource loads during SSR hydration. - "initial": Re-fetches on the client after hydration. #### `storage` + - **Type:** `(init: T | undefined) => [Accessor, Setter]` - **Default:** `createSignal` Custom storage function for the resource value, useful for persistence or custom state management. #### `onHydrated` + - **Type:** `(k: S | undefined, info: { value: T | undefined }) => void` - **Default:** `undefined` @@ -144,46 +160,45 @@ Callback fired when the resource hydrates on the client side. Returns a tuple containing the resource accessor and resource actions. -### `Resource` +### `Resource` ```typescript type Resource = { - (): T | undefined - state: "unresolved" | "pending" | "ready" | "refreshing" | "errored" - loading: boolean - error: any - latest: T | undefined -} + (): T | undefined; + state: "unresolved" | "pending" | "ready" | "refreshing" | "errored"; + loading: boolean; + error: any; + latest: T | undefined; +}; ``` - `state`: Current state of the resource. -See table below for state descriptions. + See table below for state descriptions. - `loading`: Indicates if the resource is currently loading. - `error`: Error information if the resource failed to load. - `latest`: The latest value of the resource. -| State | Description | Loading | Error | Latest | -| ------ | ----------- | ------- | ----- | ------ | -| `unresolved` | Initial state, not yet fetched | `false` | `undefined` | `undefined` | -| `pending` | Fetching in progress | `true` | `undefined` | `undefined` | -| `ready` | Successfully fetched | `false` | `undefined` | `T` | -| `refreshing` | Refetching while keeping previous value | `true` | `undefined` | `T` | -| `errored` | Fetching failed | `false` | `any` | `undefined` | - +| State | Description | Loading | Error | Latest | +| ------------ | --------------------------------------- | ------- | ----------- | ----------- | +| `unresolved` | Initial state, not yet fetched | `false` | `undefined` | `undefined` | +| `pending` | Fetching in progress | `true` | `undefined` | `undefined` | +| `ready` | Successfully fetched | `false` | `undefined` | `T` | +| `refreshing` | Refetching while keeping previous value | `true` | `undefined` | `T` | +| `errored` | Fetching failed | `false` | `any` | `undefined` | ### `ResourceActions` ```typescript type ResourceActions = { - mutate: (value: T | undefined) => T | undefined - refetch: (info?: R) => Promise | T | undefined -} + mutate: (value: T | undefined) => T | undefined; + refetch: (info?: R) => Promise | T | undefined; +}; ``` - `mutate`: Function to Manually overwrite the resource value without calling the fetcher. -Allows you to optimistically update the resource value locally, without making a network request. + Allows you to optimistically update the resource value locally, without making a network request. - `refetch`: Function to re-run the fetcher without changing the source. -If a parameter is provided to `refetch`, it will be passed to the fetcher's `refetching` property. + If a parameter is provided to `refetch`, it will be passed to the fetcher's `refetching` property. ## Examples @@ -191,8 +206,8 @@ If a parameter is provided to `refetch`, it will be passed to the fetcher's `ref ```typescript const [data] = createResource(async () => { - const response = await fetch('/api/data'); - return response.json(); + const response = await fetch("/api/data"); + return response.json(); }); // Access data @@ -207,8 +222,8 @@ console.log(data.state); // "pending" → "ready" const [userId, setUserId] = createSignal(1); const [user] = createResource(userId, async (id) => { - const response = await fetch(`/api/users/${id}`); - return response.json(); + const response = await fetch(`/api/users/${id}`); + return response.json(); }); // Automatically refetches when userId changes @@ -224,7 +239,7 @@ const [posts, { refetch, mutate }] = createResource(fetchPosts); await refetch(); // Optimistic update -mutate(posts => [...posts, newPost]); +mutate((posts) => [...posts, newPost]); ``` ### Error handling @@ -245,10 +260,9 @@ const [data] = createResource(async () => { ### With Initial Value ```typescript -const [user] = createResource( - () => fetchUser(), - { initialValue: { name: 'Loading...', id: 0 } } -); +const [user] = createResource(() => fetchUser(), { + initialValue: { name: "Loading...", id: 0 }, +}); // user() is never undefined console.log(user().name); // "Loading..." initially @@ -260,7 +274,7 @@ console.log(user().name); // "Loading..." initially const [isEnabled, setIsEnabled] = createSignal(false); const [data] = createResource( - () => isEnabled() && userId(), // Only fetches when enabled and userId exists - async (id) => fetchUserData(id) + () => isEnabled() && userId(), // Only fetches when enabled and userId exists + async (id) => fetchUserData(id) ); ``` diff --git a/src/routes/reference/basic-reactivity/create-signal.mdx b/src/routes/reference/basic-reactivity/create-signal.mdx index f59c092f3..a21608575 100644 --- a/src/routes/reference/basic-reactivity/create-signal.mdx +++ b/src/routes/reference/basic-reactivity/create-signal.mdx @@ -9,7 +9,7 @@ tags: - reactivity - core - primitives -version: '1.0' +version: "1.0" description: >- Create reactive state with createSignal, Solid's fundamental primitive. Track values that change over time and automatically update your UI when they do. @@ -27,28 +27,28 @@ import { createSignal } from "solid-js"; ## Type Signature ```typescript -function createSignal(): Signal -function createSignal(value: T, options?: SignalOptions): Signal +function createSignal(): Signal; +function createSignal(value: T, options?: SignalOptions): Signal; ``` ### Related Types ```typescript -type Signal = [get: Accessor, set: Setter] +type Signal = [get: Accessor, set: Setter]; -type Accessor = () => T +type Accessor = () => T; type Setter = { - (value: Exclude | ((prev: T) => U)): U; - (value: (prev: T) => U): U; - (value: Exclude): U; - (value: Exclude | ((prev: T) => U)): U; -} + (value: Exclude | ((prev: T) => U)): U; + (value: (prev: T) => U): U; + (value: Exclude): U; + (value: Exclude | ((prev: T) => U)): U; +}; interface SignalOptions { - name?: string; - equals?: false | ((prev: T, next: T) => boolean); - internal?: boolean; + name?: string; + equals?: false | ((prev: T, next: T) => boolean); + internal?: boolean; } ``` @@ -56,18 +56,18 @@ interface SignalOptions { ### `value` -- **Type:** `T` +- **Type:** `T` - **Default:** `undefined` The initial value for the signal. If no initial value is provided, the signal's type is automatically extended with `undefined`. -### `options` +### `options` -- **Type:** `SignalOptions` +- **Type:** `SignalOptions` - **Default:** `undefined` Configuration object for the signal. -In production mode, all debugging metadata is stripped away for optimal performance. +In production mode, all debugging metadata is stripped away for optimal performance. Dev-only options like `name` are ignored, and no warnings are issued, ensuring that your application runs as efficiently as possible. #### `name` @@ -84,17 +84,16 @@ The name will show up in console messages and in the [Solid devtools](https://gi - **Default:** `false` By default, signals use reference equality (`===`). -A custom comparison function to determine when the signal should update. +A custom comparison function to determine when the signal should update. If set to `false`, the signal will always update regardless of value equality. This can be useful to create a Signal that triggers manual updates in the reactive system, but must remain a pure function. - #### `internal` - **Type:** `boolean` - **Default:** `false` -Marks the signal as internal, preventing it from appearing in development tools. +Marks the signal as internal, preventing it from appearing in development tools. This is primarily used by Solid's internal systems. ## Return Value @@ -123,5 +122,4 @@ function Counter() { ); } - -``` \ No newline at end of file +``` diff --git a/src/routes/reference/secondary-primitives/create-computed.mdx b/src/routes/reference/secondary-primitives/create-computed.mdx index 7e70a5d4b..84da443c4 100644 --- a/src/routes/reference/secondary-primitives/create-computed.mdx +++ b/src/routes/reference/secondary-primitives/create-computed.mdx @@ -125,4 +125,4 @@ function UserEditor(props: UserEditorProps) { ## Related - [`createMemo`](/reference/basic-reactivity/create-memo) -- [`createRenderEffect`](/reference/secondary-primitives/create-render-effect) \ No newline at end of file +- [`createRenderEffect`](/reference/secondary-primitives/create-render-effect)