Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

createPresence effect reads and writes mountedItem (Solid 2 EFFECT_WRITES_OWN_SOURCE)

Open Beginner friendly
#1,082 0 comments 0 reactions 0 assignees View on GitHub

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/presence 1.0.0-next.2 (same effect on main / 1.0.0-next.4)
  • solid-js 2.0.0-rc.15
  • @kobalte/core 2.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

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from solidjs-community/solid-primitives

All issues in solidjs-community/solid-primitives

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.