Vue Composables: The Shared State Trap (+ Cheat Sheet)
You build a useCounter() composable, drop <Counter /> on the page twice, and click the first button. Both counters go up. You didn't copy-paste a bug. You wrote twelve lines of completely ordinary-looking Composition API code, and Vue executed every one of them correctly. The surprise isn't a Vue bug — it's a gap in your mental model of what a composable actually is , and that gap is exactly…
The issue arises when two instances of a composable, such as `useCounter()`, are used on the same page and both counters share the same state. This occurs due to the default behavior of JavaScript's scoping rules, where state declared inside the function is created fresh every time the function runs, resulting in private state for each instance.
However, state declared outside the function, at the module scope, is created only once, the first time anything imports the module, and subsequent calls to `useCounter()` return a reference to that same ref. This can lead to confusion and unexpected behavior, as demonstrated by the shared state of both counters in this scenario.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.