Question presented to candidate:
"You are writing a composable library. Why would you clean up with onScopeDispose and effectScope instead of onUnmounted, and how would you build a composable that several components share without duplicating its watchers?"
What a strong answer should cover:
- Composables are called from components, Pinia stores, other composables and tests;
onUnmountedworks only in the first and warns elsewhere. onScopeDisposeattaches cleanup to whatever scope is active, which inside a component is the component scope, so it covers every case.- Effects created after an
awaitor in a callback are not owned by any scope and leak; capture a scope synchronously andscope.run()later. - Shared composables: run the composable once in a detached
effectScope(true), count consumers, andstop()when the last one disposes (the pattern behind VueUsecreateSharedComposable). - Testing: run a composable inside
effectScope()and callstop()to assert cleanup, no component mount needed. - Use
getCurrentScope()to make cleanup optional when the composable may run outside any scope.
Clarifying questions expected:
- "Will this composable be used inside Pinia stores or only in components?"
- "Should several components share one instance of the state, or get their own?"
Code / implementation expected: Yes β a shared composable with reference counting, or a demonstration of an async watcher leak and its fix.