vue2中的provide与inject踩坑

背景

今天有一个孙组件需要部分数据的情况,因为子组件与父组件是之前同事已经写好了的。我不想增加props改动太多(实则就是偷懒),就想着用上之前官方不推荐使用的provideinject来实现功能。谁知道直接踩坑上,故记录一下。

版本一

// 父组件
export default {
    // ...
    provide: {
        app: this
    }
    // ...
}

// 孙组件 
export default {
    inject: ['app'],
    mounted() {
        console.log(this.app)   // undefined
    }
}

版本二

// 父组件
export default {
    // ...
    provide: () => ({
        app: this
    })
    // ...
}

// 孙组件 
export default {
    inject: ['app'],
    mounted() {
        console.log(this.app)   // undefined
    }
}

版本三 (正确的写法)

// 父组件
export default {
    // ...
    provide: function() (
    return {
        app: this
    })
    // ...
}

// 孙组件 
export default {
    inject: ['app'],
    mounted() {
        console.log(this.app)
    }
}

原因

版本一 实在baidu到的里面无数人博客复制来的写法,但是我写的不对的原因是因为 例子们不是单文件组件的写法,只能说仅供于学习,实际项目中使用还是要注意。

有查看一下源码,了解了一些provideinject的实现,从而得知了写法的问题

源码位置: vue\src\core\instance

// provide 部分
export function initProvide (vm: Component) {
  const provide = vm.$options.provide
  if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)    // 如果是方法 则将自己 作为方法的this执行方法
      : provide         // 如果不是方法 则直接返回,严格模式下 this 为 undefined
  }
}


// inject 的实现部分
export function resolveInject (inject: any, vm: Component): ?Object {
  if (inject) {
    // inject is :any because flow is not smart enough to figure out cached
    const result = Object.create(null)
    const keys = hasSymbol
      ? Reflect.ownKeys(inject)
      : Object.keys(inject)

    for (let i = 0; i < keys.length; i++) {
      const key = keys[i]
      // #6574 in case the inject object is observed...
      if (key === '__ob__') continue
      const provideKey = inject[key].from
      let source = vm
      while (source) {
        if (source._provided && hasOwn(source._provided, provideKey)) {
          result[key] = source._provided[provideKey]
          break
        }
        source = source.$parent  // 自己未定义 则一直往上寻找
      }
      if (!source) {
        if ('default' in inject[key]) {
          const provideDefault = inject[key].default
          result[key] = typeof provideDefault === 'function'
            ? provideDefault.call(vm)
            : provideDefault
        } else if (process.env.NODE_ENV !== 'production') {
          warn(`Injection "${key}" not found`, vm)
        }
      }
    }
    return result
  }
}

代码还是很简单的,可以参考 https://www.jb51.net/article/226645.htm 这个地址来查看一些参考

后记

很多东西还是要自己实际用一下才知道有什么问题,当然其实这个也只是因为一些写法上的问题导致的结果不达预期。

其次是 还是不太推荐 使用provideinject,特别是当前这个直接返回vue实例的行为。因为这个的能力实在有些太大了,很容易导致管理不当的混乱。比如在孙组件中直接this.app.xx = 123这个行为其实完全打乱了数据管理。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、组件间怎么传值,具体说说代码怎样实现 子传父:子向父是通过 events($emit);通过父链 / 子链也可...
    如也_d1c0阅读 789评论 0 1
  • **1、组件间怎么传值,具体说说代码怎样实现 ** 子传父:子向父是通过 events($emit);通过父链 /...
    北冥有鱼_425c阅读 431评论 2 7
  • 1、组件间怎么传值,具体说说代码怎样实现 子传父:子向父是通过 events($emit);通过父链 / 子链也可...
    好名字都让你们用了阅读 1,727评论 0 34
  • 1、组件间怎么传值,具体说说代码怎样实现 子传父:子向父是通过 events($emit);通过父链 / 子链也可...
    chang_遇见缘阅读 4,048评论 12 87
  • 生命周期函数面试题 1.什么是Vue生命周期?vue生命周期是指vue是对象从创建到销毁的过程。 2.Vue生命周...
    Angel_6c4e阅读 16,782评论 2 51