非父子通信: provide和inject

一、核心概念

  1. 作用:允许祖先组件 (provider)向任意层级后代(injector)传递数据,而无需经过每一层 props 逐级下发或事件逐级上报。

  2. 语义:

    • provide:在祖先组件里"声明"要下发的数据。

    • inject:在后代组件里"声明"要接收的数据。

  3. 响应式差异:

    • Vue2 默认不具备响应式联动(provide 的值在运行时变了,后代不会自动更新)。

    • Vue3 只要 provide 的是 ref / reactive 对象,后代就能自动追踪变化。

二、Vue2 示例(Options API)

javascript 复制代码
<template>
  <div>
    <h3>根组件 (Vue2) 主题: {{theme}}</h3>
    <button @click="toggleTheme">切换主题</button>
    <hr>
    <Child/>
  </div>
</template>

<script>
import Child from './Child.vue'

export default {
  components: { Child },
  data() {
    return {
      theme: 'light'          // 普通字符串,非响应式
    }
  },
  provide() {                 // 关键点1:函数写法,才能访问 this
    return {
      theme: this.theme,      // 注意:仅初始化时快照,后续变化不会同步
      toggleTheme: this.toggleTheme
    }
  },
  methods: {
    toggleTheme() {
      this.theme = this.theme === 'light' ? 'dark' : 'light'
    }
  }
}
</script>

子孙组件

javascript 复制代码
<template>
  <div style="margin-left: 40px;">
    <p>孙子组件拿到主题:{{theme}}</p>
    <button @click="toggleTheme">孙子触发切换</button>
  </div>
</template>

<script>
export default {
  inject: ['theme', 'toggleTheme'],   // 关键点2:数组语法
  created() {
    console.log('Vue2 inject 到的数据:', this.theme)
  }
}
</script>

运行结果:

  • 初始能读到 theme;

  • 根组件按钮可切换,但孙子不会自动刷新(非响应式)。

三、Vue3 示例(Composition API)

javascript 复制代码
<template>
  <div>
    <h3>根组件 (Vue3) 主题: {{theme}}</h3>
    <button @click="toggleTheme">切换主题</button>
    <hr>
    <Child/>
  </div>
</template>

<script setup>
import { provide, ref, readonly } from 'vue'
import Child from './Child.vue'

const theme = ref('light')
function toggleTheme() {
  theme.value = theme.value === 'light' ? 'dark' : 'light'
}
// 关键点1:使用 provide(key, value)
provide('theme', readonly(theme))      // 只读保护,防止被随意修改
provide('toggleTheme', toggleTheme)
</script>

子孙组件

javascript 复制代码
<template>
  <div style="margin-left: 40px;">
    <p>孙子组件拿到主题:{{theme}}</p>
    <button @click="toggleTheme">孙子触发切换</button>
  </div>
</template>

<script setup>
import { inject } from 'vue'

const theme = inject('theme')            // 关键点2: inject(key, 默认值?)
const toggleTheme = inject('toggleTheme')

// 默认值示例
const user = inject('user', { name: 'Guest' })
</script>

运行结果:

  • 根组件切换按钮,孙子立即同步刷新(响应式)。

四、常见陷阱速查

  1. Vue2 中 provide 写成对象而非函数,导致访问不到实例属性。

  2. 把非响应式字面量(如普通字符串、数字)provide 出去,后期改动后代看不到。

  3. 直接修改 inject 拿到的响应式对象,会绕过单向数据流;最好 provide('xxx', readonly(xxx))

  4. 跨组件层级很深时,provide/inject 比 EventBus 或 Vuex/Pinia 更轻量;但全局状态仍推荐官方状态管理库。

相关推荐
AALoveTouch9 分钟前
大麦网协议分析
javascript·python
●VON19 分钟前
React Native for OpenHarmony:2048 小游戏的开发与跨平台适配实践
javascript·学习·react native·react.js·von
木斯佳37 分钟前
前端八股文面经大全:26届秋招滴滴校招前端一面面经-事件循环题解析
前端·状态模式
光影少年1 小时前
react状态管理都有哪些及优缺点和应用场景
前端·react.js·前端框架
晚烛2 小时前
CANN + 物理信息神经网络(PINNs):求解偏微分方程的新范式
javascript·人工智能·flutter·html·零售
saber_andlibert2 小时前
TCMalloc底层实现
java·前端·网络
逍遥德2 小时前
如何学编程之01.理论篇.如何通过阅读代码来提高自己的编程能力?
前端·后端·程序人生·重构·软件构建·代码规范
冻感糕人~3 小时前
【珍藏必备】ReAct框架实战指南:从零开始构建AI智能体,让大模型学会思考与行动
java·前端·人工智能·react.js·大模型·就业·大模型学习
程序员agions3 小时前
2026年,“配置工程师“终于死绝了
前端·程序人生
alice--小文子3 小时前
cursor-mcp工具使用
java·服务器·前端