uni-app 组件之间的循环引用 A->B->A 导致 A 不渲染 dom
uni-app 组件之间的循环引用 A->B->A 导致 A 不渲染 dom
| 开发环境 | 版本号 | 项目创建方式 |
|---|---|---|
| Windows | win10 | HBuilderX |
示例代码:
<template>
<view class="page">
<b-test></b-test>
</view>
</template>
<script>
export default {
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
.page {
width: 100%;
height: 100%;
padding: 100px;
}
</style>
<template>
<view>
<text>{{ isChild ? "subAAA" : "AAA" }}</text>
<view v-if="!isChild">
<b-subtest></b-subtest>
</view>
</view>
</template>
<script>
export default {
name: "b-test",
props: {
isChild: {
type: Boolean,
default() {
return false;
},
},
},
data() {
return {};
},
created() {},
};
</script>
<template>
<view>
<text>subBBB</text>
<b-test :isChild="true"></b-test>
</view>
</template>
<script>
export default {
name: "b-subtest",
components: {
bTest: () => import("../b-test/b-test"),
},
data() {
return {};
},
created() {},
};
</script>
操作步骤:
无
预期结果:
AAA
subBBB
subAAA
实际结果:
AAA
subBBB
更多关于uni-app 组件之间的循环引用 A->B->A 导致 A 不渲染 dom的实战教程也可以访问 https://www.itying.com/category-93-b0.html
4 回复
兄弟你解决了吗?
更多关于uni-app 组件之间的循环引用 A->B->A 导致 A 不渲染 dom的实战教程也可以访问 https://www.itying.com/category-93-b0.html
这个是不是uniapp不支持啊,我也遇到同样的问题
组件的循环引用用到了异步组件,App端不支持异步组件,需要把组件定义到全局。
循环引用是 Vue 生态中的常见问题,在 uni-app 中同样存在。您遇到的问题正是典型的组件循环引用(A->B->A)导致渲染失败的情况。
问题分析:
- 在
b-test组件中,通过条件渲染引用了b-subtest组件 - 在
b-subtest组件中,又异步引用了b-test组件(通过:isChild="true") - 当 Vue 尝试解析组件依赖时,陷入了无限循环:
b-test→b-subtest→b-test→ …
解决方案:
方案一:使用同步组件注册(推荐) 将异步导入改为同步导入,避免循环依赖解析时的时序问题:
<!-- b-subtest.vue -->
<script>
import BTest from "../b-test/b-test.vue";
export default {
name: "b-subtest",
components: {
bTest: BTest, // 改为同步导入
},
// ... 其他代码
};
</script>
方案二:调整组件结构设计 重新考虑组件关系,避免循环引用:
- 将公共逻辑提取到 mixin 或 composable 函数中
- 使用插槽(slot)来解耦组件依赖
- 考虑将
b-test中的子组件逻辑内聚,避免拆分为两个相互引用的组件
方案三:使用动态组件 在父级组件中控制组件渲染,打破循环:
<!-- 父组件中 -->
<template>
<component :is="currentComponent" :isChild="isChild"></component>
</template>
方案四:延迟渲染
使用 v-if 或 nextTick 控制渲染时机:
<!-- b-subtest.vue -->
<template>
<view>
<text>subBBB</text>
<b-test v-if="showChild" :isChild="true"></b-test>
</view>
</template>
<script>
export default {
data() {
return {
showChild: false
};
},
mounted() {
this.$nextTick(() => {
this.showChild = true;
});
}
};
</script>

