Lifecycle & Actions

onSettled

Schedules callback to run once after the reactive graph has fully settled — i.e. Once every pending async read inside the current owner has resolved and the queue has flushed. Each call registers a single fire; it does not create an ongoing subscription.

The canonical lifecycle primitive in 2.0. Three main usages:

  • Component-level setup-and-teardown (the most common shape): run setup after the component's first stable render and return a cleanup function to dispose it on owner disposal. This is the replacement for the 1.x onMount + onCleanup pairing — setup and teardown live in one block, and onCleanup is no longer the right tool for component bodies. (onMount no longer exists in 2.0.)
  • Post-settle "ready" hook: run once after a component's first stable render — analytics ping, focus, scroll-into-view, etc. No cleanup needed.
  • Inside an event handler: schedule work to run after the action / transition triggered by the event has completed.

Reactive reads inside the callback are not tracked — to react to subsequent settles, register a new onSettled each time.

onCleanup is not allowed inside the callback — return a cleanup function instead. The returned cleanup runs on owner disposal.

A cleanup return is only honored when onSettled is called from an owned scope (e.g. A component body). When it fires out of band from an unowned scope — an event handler, a tracked effect, or another onSettled — there is no owner lifecycle to bind a cleanup to; returning one is a dev-mode error (and is dropped in production). Use the post-settle/event-handler forms below for one-shot work, and keep setup-with-teardown in an owned scope.


Import

import { onSettled } from "solid-js";

Type signature

function onSettled(callback: () => void | (() => void)): void;

Parameters

callback

Function to run; may return a cleanup function that fires on owner disposal


Examples

// Component-level setup + teardown — replaces onMount + onCleanup.
// Subscribe to an external source on mount, unsubscribe on dispose.
function useViewportWidth() {
const [width, setWidth] = createSignal(window.innerWidth);
onSettled(() => {
const onResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
});
return width;
}
// Post-settle "ready" hook — no cleanup needed.
function Dashboard() {
const data = createMemo(async () => fetchData());
onSettled(() => {
analytics.track("dashboard.ready");
});
return (
<Loading fallback={<Spinner />}>
<pre>{data()}</pre>
</Loading>
);
}
// Event-handler — runs after the action settles.
function SaveButton() {
const save = action(function* () {
yield api.save();
});
const handleClick = () => {
save();
onSettled(() => toast("Saved!"));
};
return <button onClick={handleClick}>Save</button>;
}
Last updated: 7/4/26, 6:21 PMEdit this pageReport an issue with this page