import {
reactive,
computed,
- watchEffect,
onMounted,
onUnmounted,
- next,
- nextTick,
+ watchPostEffect,
} from 'vue'
const STORAGE_KEY = 'todos-vuejs-3.x'
}),
})
-watchEffect(() => {
+watchPostEffect(() => {
todoStorage.save(state.todos)
})
}
// vapor custom directive
-const vTodoFocus = (el, value) => () => {
- if (value()) nextTick(() => el.focus())
+const vTodoFocus = (el, value) => {
+ watchPostEffect(() => value() && el.focus())
}
</script>
--- /dev/null
+import { effectScope, ref } from '@vue/reactivity'
+import { type VaporDirective, withVaporDirectives } from '../../src'
+import { nextTick, watchEffect } from '@vue/runtime-dom'
+
+describe('custom directive', () => {
+ it('should work', async () => {
+ const teardown = vi.fn()
+ const dir: VaporDirective = vi.fn((el, source) => {
+ watchEffect(() => {
+ el.textContent = source()
+ })
+ return teardown
+ })
+ const scope = effectScope()
+ const el = document.createElement('div')
+ const n = ref(1)
+ const source = () => n.value
+ const modifiers = { mod: true }
+ scope.run(() => {
+ withVaporDirectives(el, [[dir, source, undefined, modifiers]])
+ })
+ expect(dir).toHaveBeenCalledWith(el, source, undefined, modifiers)
+ expect(teardown).not.toHaveBeenCalled()
+
+ expect(el.textContent).toBe('1')
+
+ n.value = 2
+ await nextTick()
+ expect(el.textContent).toBe('2')
+
+ scope.stop()
+ expect(teardown).toHaveBeenCalled()
+
+ n.value = 3
+ await nextTick()
+ // should be stopped and not update
+ expect(el.textContent).toBe('2')
+ })
+})
-import type { DirectiveModifiers } from '@vue/runtime-dom'
+import { type DirectiveModifiers, onScopeDispose } from '@vue/runtime-dom'
import type { VaporComponentInstance } from '../component'
-import { renderEffect } from '../renderEffect'
// !! vapor directive is different from vdom directives
export type VaporDirective = (
type VaporDirectiveArguments = Array<
| [VaporDirective | undefined]
| [VaporDirective | undefined, () => any]
- | [VaporDirective | undefined, () => any, argument: string]
+ | [VaporDirective | undefined, (() => any) | undefined, argument: string]
| [
VaporDirective | undefined,
- value: () => any,
- argument: string,
+ value: (() => any) | undefined,
+ argument: string | undefined,
modifiers: DirectiveModifiers,
]
>
for (const [dir, value, argument, modifiers] of dirs) {
if (dir) {
const ret = dir(node, value, argument, modifiers)
- if (ret) renderEffect(ret)
+ if (ret) onScopeDispose(ret)
}
}
}