docs: document ref callback ownership change in migration guide - #3001
docs: document ref callback ownership change in migration guide#3001waterWang wants to merge 1 commit into
Conversation
|
ryansolid
left a comment
There was a problem hiding this comment.
Thanks — this fills a real gap, and the technical claims all check out against the implementation: the runtime applies refs with runWithOwner(null, ...) (deliberately, to match the unowned apply phase of directive factories), and onSettled from a component body does accept a returned cleanup.
Two suggestions on the examples before this lands:
- The 1.x "before" registers a cleanup for a listener that's never added, and the 2.0 "after" splits the teardown from setup that isn't shown. Pairing setup and teardown makes the migration self-contained and matches
onSettled's documented replaces-onMount+onCleanup form:
// 1.x — ref callback ran owned, so cleanup could live inside it
<div ref={(el) => {
el.addEventListener("pointerdown", onDown);
onCleanup(() => el.removeEventListener("pointerdown", onDown));
}} />// 2.0 — the ref callback is unowned; keep setup + teardown in the owned
// component scope and let the ref only capture the element
let el;
onSettled(() => {
el.addEventListener("pointerdown", onDown);
return () => el.removeEventListener("pointerdown", onDown);
});
<div ref={el} />- Worth one closing sentence that for reusable element-attached behavior, the directive-factory pattern in the next section is the fuller answer — setup phase owned (primitives,
onCleanup), apply phase unowned — so readers don't reach for module-levelonSettledplumbing everywhere.
The checklist line and placement are good as-is.
|
To make point 2 concrete rather than a pointer — the section would be complete if it showed the directive-factory form of the same advice, with the cleanup in the owned top half: // Reusable form: the factory's setup half IS the owned scope —
// primitives and onCleanup live there; the returned apply callback
// (the actual ref) is unowned and only touches the element.
function tooltip(options) {
let el;
const instance = createTooltipInstance();
createEffect(
() => options.content,
content => el && instance.setContent(content)
);
onCleanup(() => instance.destroy());
return nextEl => {
el = nextEl;
instance.attach(nextEl);
};
}
<button ref={tooltip({ content: "Save" })} />Same principle as the |
Ref callbacks in 2.0 run unowned (getOwner() is null), so the 1.x pattern of registering onCleanup inside the callback no longer works. Documents both owned-scope packagings: inline onSettled for one-off component-local behavior, and the directive factory's setup half for reusable behavior — plus the timing difference between them. Supersedes PR #3001. Co-authored-by: waterWang <waterWang@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
|
Thanks for identifying this gap and taking a first pass — the core claim was exactly right. Rather than iterate on the examples across review rounds while the guide is moving with the beta, we've landed the section directly in 525073c, incorporating your checklist line and subsection structure with the reworked examples from the review (paired setup/teardown in Note the docs-site side of this is tracked separately as solidjs/solid-docs#1630 — this repo's MIGRATION.md is the internal migration reference, so that issue still needs its own PR against the docs repo if you'd like to carry it there. |
docs: document ref callback ownership change in migration guide
Description
In Solid 2.0, ref callbacks are no longer owned —
getOwner()returnsnullinside a ref callback, so 1.x-style cleanup registration (usingonCleanup()inside the ref callback) no longer works.This change is documented but not mentioned in the migration guide, which can be confusing for developers migrating from 1.x who relied on the old behavior.
Changes
### Ref callbacks: no longer ownedsubsection with before/after code examples showing how to handle cleanup in 2.0Fixes solidjs/solid-docs#1630