Vue2 Composition API下如何实现provide/inject响应式?
Vue2 + Composition API:Provide/Inject 响应式失效问题
环境版本
- Vue.js 2
- Composition API
问题描述
父组件通过provide提供响应式变量status,并在mounted钩子中定时修改其值;子组件用inject获取该值后,监听injStatus的watch未触发,无法捕获值的变化。
父组件代码
<template> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld></HelloWorld> </template> <script> import {computed} from 'vue' import {InjectionKeys} from './assets/InjectionKeys.js' import {HelloWorld} from './components/HelloWorld.vue' export default { name: 'App', components: { HelloWorld }, data() { return { status:undefined }; }, provide() { return { [InjectionKeys.PROVIDE_KEY_STATUS.description]: computed(() => this.compPropsStatus), }; }, computed:{ compPropsStatus() { return this.status }, }, mounted() { setTimeout(() => { this.status = '1' }, 1000); setTimeout(() => { this.status = '2' }, 3000); setTimeout(() => { this.status = '3' }, 5000); setTimeout(() => { this.status = '4' }, 7000); } } </script>
子组件代码
<script> import {InjectionKeys} from '../assets/InjectionKeys.js' export default { name: 'HelloWorld', props: { msg: String }, inject: { injStatus: { from: InjectionKeys.PROVIDE_KEY_STATUS.description }, }, watch:{ injStatus(newVal, oldVal) { console.log({msg:' watched injStatus. oldVal:' + oldVal + ', and newVal: ', newVal}); }, }, } </script>
解决方案
方案1:改用Composition API的setup注入并监听
在子组件中使用setup函数,通过Composition API的inject和watch方法实现响应式监听:
<script> import { inject, watch } from 'vue' import { InjectionKeys } from '../assets/InjectionKeys.js' export default { name: 'HelloWorld', props: { msg: String }, setup() { const injStatus = inject(InjectionKeys.PROVIDE_KEY_STATUS.description) watch(injStatus, (newVal, oldVal) => { console.log({msg: ' watched injStatus. oldVal:' + oldVal + ', and newVal: ', newVal}) }) return { injStatus } } } </script>
方案2:提供响应式对象而非单独值
将status包装在响应式对象中提供,利用Vue对对象属性的响应式追踪特性:
父组件修改:
<script> import { reactive } from 'vue' import { InjectionKeys } from './assets/InjectionKeys.js' import { HelloWorld } from './components/HelloWorld.vue' export default { name: 'App', components: { HelloWorld }, data() { return { statusObj: reactive({ status: undefined }) }; }, provide() { return { [InjectionKeys.PROVIDE_KEY_STATUS.description]: this.statusObj }; }, mounted() { setTimeout(() => { this.statusObj.status = '1' }, 1000); setTimeout(() => { this.statusObj.status = '2' }, 3000); setTimeout(() => { this.statusObj.status = '3' }, 5000); setTimeout(() => { this.statusObj.status = '4' }, 7000); } } </script>
子组件修改:
<script> import { InjectionKeys } from '../assets/InjectionKeys.js' export default { name: 'HelloWorld', props: { msg: String }, inject: { statusObj: { from: InjectionKeys.PROVIDE_KEY_STATUS.description }, }, watch:{ 'statusObj.status'(newVal, oldVal) { console.log({msg:' watched status. oldVal:' + oldVal + ', and newVal: ', newVal}); }, }, } </script>
原因说明
Vue2的Options API中,直接监听inject获取的计算属性时,watch机制无法正确追踪其依赖变化。改用Composition API的watch可直接监听响应式值;而提供响应式对象的方式,是利用了Vue对对象属性的响应式追踪逻辑——只要对象引用不变,内部属性的变化就能被监听到。
内容的提问来源于stack exchange,提问作者user22470297
相关产品推荐
相关产品推荐

