createPresence effect reads and writes mountedItem (Solid 2 EFFECT_WRITES_OWN_SOURCE)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 85/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- typescript
- Domain
- frontend
Research direction
Start in packages/presence/src/index.ts around the createPresence effect at lines 161–174, and read how item() and isMounted() drive its updates. The issue provides a suggested repair using Solid 2's createEffect(compute, apply) and untrack(mountedItem). Reproduce by opening the button in the supplied example; done when that interaction no longer reports EFFECT_WRITES_OWN_SOURCE and exit-then-swap behavior remains intact.
Written by the indexing model from the issue text.
Description
Describe the bug
createPresence keeps the mounted item in sync with an effect that both reads mountedItem() and writes it with setMountedItem. On Solid 2 that is EFFECT_WRITES_OWN_SOURCE: the effect re-runs because of its own write, settles in two flushes, and the first frame renders the pre-write value.
mountedItem only needs to be sampled when item() or isMounted() changes. It should not be a tracked input of the effect that writes it.
This shows up when opening a Kobalte Popover (@kobalte/[email protected]). Popover calls createPresence(() => forceMount || isOpen() || undefined, { transitionDuration: 0 }). The dev console reports:
[EFFECT_WRITES_OWN_SOURCE] effect "effect" re-ran because of its own write: it wrote "signal", which fed back into its inputs. Two flushes to settle, and the screen rendered the pre-write value in between. The written value is a function of what the effect reads — compute it in a memo (or normalize where the source is written) instead of correcting it after the fact.
in <Popover> › effect
The same effect is in packages/presence/src/index.ts on main (1.0.0-next.4) and in the published 1.0.0-next.2 build. The published build already splits this into Solid 2's createEffect(compute, apply), but the compute still tracks mountedItem().
createEffect(() => {
if (mountedItem() !== item()) {
if (isMounted()) {
setShouldBeMounted(false);
} else if (itemShouldBeMounted(item())) {
setMountedItem(() => item());
setShouldBeMounted(true);
}
} else if (!itemShouldBeMounted(item())) {
setShouldBeMounted(false);
} else if (itemShouldBeMounted(item())) {
setShouldBeMounted(true);
}
});
Suggested repair
Track item() and isMounted() only. Read the previous item with untrack(mountedItem) in the apply. Exit-then-swap stays: a change while still mounted only calls setShouldBeMounted(false); the swap still runs on the later pass, because that pass is driven by isMounted() becoming false, not by the mountedItem write.
createEffect(
() => [item(), isMounted()] as const,
([currentItem, isM]) => {
const mounted = untrack(mountedItem);
if (mounted !== currentItem) {
if (isM) setShouldBeMounted(false);
else if (itemShouldBeMounted(currentItem)) {
setMountedItem(() => currentItem);
setShouldBeMounted(true);
}
} else if (!itemShouldBeMounted(currentItem)) setShouldBeMounted(false);
else if (itemShouldBeMounted(currentItem)) setShouldBeMounted(true);
},
);
Reproduction
import { createSignal } from "solid-js";
import { createPresence } from "@solid-primitives/presence";
export default function App() {
const [open, setOpen] = createSignal(false);
createPresence(open, { transitionDuration: 0 });
return <button onClick={() => setOpen(true)}>Open</button>;
}
Click Open. The dev console reports EFFECT_WRITES_OWN_SOURCE as above.
Versions
@solid-primitives/presence1.0.0-next.2(same effect onmain/1.0.0-next.4)solid-js2.0.0-rc.15@kobalte/core2.0.0-alpha.4(how we hit it; the bug is in presence)
- Dominant language
- TypeScript
- Stars
- 1.6k
- Forks
- 165
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 15
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from solidjs-community/solid-primitives
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
solidjs-community/solid-primitives#1059 · 1 comment ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 48/100
solidjs-community/solid-primitives#1055 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 48/100
solidjs-community/solid-primitives#894 ·
Maintainers usually reply within 1 day
-
help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 52/100
solidjs-community/solid-primitives#830 · 2 comments ·
Maintainers usually reply within 1 day
-
help wanted
Difficulty 3/5 1-2 days Newbie friendliness 48/100
solidjs-community/solid-primitives#806 · 1 comment · 2 reactions ·
Maintainers usually reply within 1 day
All issues in solidjs-community/solid-primitives
Similar issues
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P3
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
openclaw/openclaw#182077 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
aikido high security
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
dequelabs/axe-linter-action#161 ·
-
[Feature Request] Update the DimCode agent icon to the 45:32 brand markPossibly taken @eric8810 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
lyswhut/lx-music-desktop#3026 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
abhigyanpatwari/GitNexus#3704 ·
Maintainers usually reply within 1 day