组件更新的触发条件
组件更新的触发条件
Vue3 的组件更新机制依赖于响应式系统,当响应式数据发生变化时,会触发组件的重新渲染。理解组件更新的触发条件对于深入掌握 Vue3 的工作原理至关重要。
响应式数据变更
Vue3 使用 Proxy 实现响应式系统,当响应式对象的属性被修改时,会触发依赖该属性的组件的更新。例如:
const state = reactive({ count: 0 })
// 修改 count 会触发依赖它的组件更新
state.count++
对于 ref 创建的响应式变量,修改其 value 属性同样会触发更新:
const count = ref(0)
// 修改 value 会触发更新
count.value++
props 变化
当父组件传递给子组件的 props 发生变化时,子组件会触发更新。Vue3 会对 props 进行浅层比较,只有当前 props 与之前 props 不相等时才会触发更新。
// 父组件
<Child :count="parentCount" />
// 子组件
export default {
props: ['count'],
setup(props) {
// 当 parentCount 变化时,props.count 会更新
}
}
插槽内容变化
当父组件传递给子组件的插槽内容发生变化时,子组件也会更新:
// 父组件
<Child>
<template #default>
{{ dynamicContent }}
</template>
</Child>
// 当 dynamicContent 变化时,Child 组件会更新
强制更新
虽然不推荐,但可以通过 forceUpdate
方法强制组件更新:
import { getCurrentInstance } from 'vue'
export default {
setup() {
const instance = getCurrentInstance()
const handleForceUpdate = () => {
instance.proxy.$forceUpdate()
}
return { handleForceUpdate }
}
}
异步更新队列
Vue3 的更新是异步的,会将多个数据变更合并到一个更新周期中。这意味着在同一个事件循环中多次修改响应式数据,只会触发一次组件更新:
const state = reactive({ count: 0 })
// 只会触发一次更新
state.count++
state.count++
state.count++
计算属性和侦听器
计算属性的值发生变化时,会触发依赖该计算属性的组件更新:
const state = reactive({ a: 1, b: 2 })
const sum = computed(() => state.a + state.b)
// 修改 state.a 或 state.b 会导致 sum 重新计算
// 如果 sum 的值发生变化,依赖它的组件会更新
侦听器本身不会直接触发组件更新,但可以在回调中修改其他响应式数据来间接触发更新:
watch(
() => state.count,
(newVal) => {
// 可以在这里修改其他响应式数据来触发更新
otherState.value = newVal * 2
}
)
组件实例的更新
当组件实例的某些特定属性变化时也会触发更新:
$attrs
变化$slots
变化- 通过
provide
提供的值变化且子组件使用了inject
条件渲染和列表渲染
v-if 和 v-for 指令控制的元素变化时也会触发相关组件的更新:
// 当 show 变化时,会触发 Child 组件的创建/销毁或更新
<Child v-if="show" />
// 当 list 变化时,会触发列表项的更新
<div v-for="item in list" :key="item.id">{{ item.text }}</div>
自定义指令的更新
如果组件使用了自定义指令,当指令的绑定值变化时,会触发 update 钩子,这也可能导致组件更新:
// 自定义指令
app.directive('highlight', {
updated(el, binding) {
// 当 binding.value 变化时执行
el.style.backgroundColor = binding.value
}
})
// 使用指令
<div v-highlight="color"></div>
// 当 color 变化时,会触发 update 钩子
生命周期钩子中的更新
在某些生命周期钩子中修改响应式数据会触发额外的更新:
export default {
setup() {
const count = ref(0)
onMounted(() => {
// 这会触发一次额外的更新
count.value++
})
return { count }
}
}
全局状态管理
当使用 Pinia 或 Vuex 等状态管理库时,状态变化也会触发依赖这些状态的组件更新:
// 使用 Pinia
import { useStore } from '@/stores/counter'
export default {
setup() {
const store = useStore()
// 当 store.count 变化时,组件会更新
return { count: store.count }
}
}
函数式组件的更新
函数式组件没有实例,它们的更新完全依赖于 props 的变化:
// 函数式组件
const FunctionalComponent = (props) => {
return h('div', props.text)
}
// 只有 props.text 变化时才会重新渲染
渲染函数的更新
使用 render 函数或 h 函数创建的组件,其更新条件与模板编译后的组件相同:
export default {
render() {
// 当响应式数据变化时,render 函数会重新执行
return h('div', this.count)
},
data() {
return { count: 0 }
}
}
异步组件的更新
异步组件在加载完成后会触发更新,之后的行为与普通组件相同:
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
)
// 当异步组件加载完成后,会触发一次更新
keep-alive 组件的更新
被 keep-alive 缓存的组件在激活时会触发 activated 钩子,但不会触发完整的重新渲染:
<keep-alive>
<component :is="currentComponent" />
</keep-alive>
// 切换 currentComponent 时,缓存的组件不会重新创建
// 但会触发 activated 钩子
错误处理边界的更新
当错误被错误边界捕获时,会触发错误边界组件的更新:
<ErrorBoundary>
<ChildThatMightError />
</ErrorBoundary>
// 当 ChildThatMightError 抛出错误时
// ErrorBoundary 会更新其状态并重新渲染
过渡效果的更新
使用 transition 组件时,进入/离开的过渡效果也会触发相关组件的更新:
<transition>
<div v-if="show">Content</div>
</transition>
// 当 show 变化时,会触发过渡效果
// 这涉及到组件的更新和 DOM 操作
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn