isMounted: boolean
isUnmounted: boolean
isDeactivated: boolean
+ isUpdating: boolean
bc?: LifecycleHook // LifecycleHooks.BEFORE_CREATE
c?: LifecycleHook // LifecycleHooks.CREATED
: Object.create(this.appContext.provides)
this.refs = EMPTY_OBJ
this.emitted = this.ec = this.exposed = this.propsDefaults = null
- this.isMounted = this.isUnmounted = this.isDeactivated = false
+ this.isMounted =
+ this.isUnmounted =
+ this.isUpdating =
+ this.isDeactivated =
+ false
// init props
const target = rawProps || EMPTY_OBJ
if (block instanceof Node) {
parent.insertBefore(block, anchor)
} else if (isVaporComponent(block)) {
- if (block.bm) invokeArrayFns(block.bm)
- insert(block.block, parent, anchor)
- if (block.m) invokeArrayFns(block.m)
+ if (!block.isMounted) {
+ if (block.bm) invokeArrayFns(block.bm)
+ insert(block.block, parent, anchor)
+ if (block.m) invokeArrayFns(block.m)
+ block.isMounted = true
+ } else {
+ insert(block.block, parent, anchor)
+ }
} else if (isArray(block)) {
for (let i = 0; i < block.length; i++) {
insert(block[i], parent, anchor)
import { ReactiveEffect } from '@vue/reactivity'
-import { type SchedulerJob, currentInstance, queueJob } from '@vue/runtime-dom'
+import {
+ type SchedulerJob,
+ currentInstance,
+ queueJob,
+ queuePostFlushCb,
+ setCurrentInstance,
+ warn,
+} from '@vue/runtime-dom'
+import { type VaporComponentInstance, isVaporComponent } from './component'
+import { invokeArrayFns } from '@vue/shared'
-export function renderEffect(fn: () => void): void {
- const updateFn = () => {
- fn()
+export function renderEffect(fn: () => void, noLifecycle = false): void {
+ const instance = currentInstance as VaporComponentInstance
+ if (__DEV__ && !isVaporComponent(instance)) {
+ warn('renderEffect called without active vapor instance.')
}
- const effect = new ReactiveEffect(updateFn)
+
+ const effect = new ReactiveEffect(
+ noLifecycle
+ ? fn
+ : () => {
+ const reset = setCurrentInstance(instance)
+ const { isMounted, isUpdating, bu, u } = instance
+ // before update
+ if (isMounted && !isUpdating && (bu || u)) {
+ instance.isUpdating = true
+ bu && invokeArrayFns(bu)
+ fn()
+ queuePostFlushCb(() => {
+ instance.isUpdating = false
+ u && invokeArrayFns(u)
+ })
+ } else {
+ fn()
+ }
+ reset()
+ },
+ )
+
const job: SchedulerJob = effect.runIfDirty.bind(effect)
- job.i = currentInstance as any
- job.id = currentInstance!.uid
+ job.i = instance
+ job.id = instance.uid
effect.scheduler = () => queueJob(job)
effect.run()