-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Describe the bug
Reproduction steps:
- Go to minimal repro
- Open Dev Tools to see console.log prints
- Press "Toggle component".
- Move mouse and notice that mouse coordinates are printed.
- Press "Toggle component" again to unmount component and move mouse.
Expected:
Mouse coordinate logs stop printing.
Actual:
Mouse coordinates continue to print after component is unmounted.
I was looking at how directives are implemented in VueUse and noticed that these aren't cleaned when component unmounts.
Currently VueUse directives just setup their effects within mounted hook of directives. For example useMouseInElement directive does the following:
vueuse/packages/core/useMouseInElement/directive.ts
Lines 11 to 21 in b2aa062
| export const vMouseInElement: ObjectDirective< | |
| HTMLElement, | |
| BindingValueFunction | BindingValueArray | |
| > = { | |
| mounted(el, binding) { | |
| const [handler, options] = (typeof binding.value === 'function' ? [binding.value, {}] : binding.value) as BindingValueArray | |
| const state = reactiveOmit(reactive(useMouseInElement(el, options)), 'stop') | |
| watch(state, val => handler(val)) | |
| }, | |
| } |
But when directive's mounted hook runs getCurrentScope is undefined. And VueUse composables heavily rely on it via tryOnScopeDispose utility which is used to configure cleanup routines.
We had a discussion about this issue on discord here: https://discord.com/channels/937808017016119440/937969993964978197/1408143068678455329
Seems like proper solution will require directives to create their own effect scope within a directive instance, run it in mounted and stop it in unmounted. One of the proposed solutions was along these lines
export const vDirective = {
mounted(target, binding) {
const scope = effectScope()
target._scope = scope
scope.run(()=> {
// call composable to setup its effects
// useMouseInElement(/* */)
})
},
unmounted(target){
target._scope.stop()
}
};Reproduction
System Info
System:
OS: macOS 15.6.1
CPU: (10) arm64 Apple M1 Pro
Memory: 148.69 MB / 32.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.17.1 - ~/.nvm/versions/node/v22.17.1/bin/node
Yarn: 4.9.3 - ~/.nvm/versions/node/v22.17.1/bin/yarn
npm: 10.9.2 - ~/.nvm/versions/node/v22.17.1/bin/npm
bun: 1.2.19 - ~/.bun/bin/bun
Browsers:
Chrome: 139.0.7258.155
Safari: 18.6
npmPackages:
@vueuse/core: 13.8.0 => 13.8.0
@vueuse/gesture: ^2.0.0 => 2.0.0
vue: ^3.5.20 => 3.5.20Used Package Manager
npm
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- Make sure this is a VueUse issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to https://github.com/vuejs/core instead.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion.
- The provided reproduction is a minimal reproducible example of the bug.