美文网首页
vue2中的provide与inject踩坑

vue2中的provide与inject踩坑

作者: 这是一个无趣人 | 来源:发表于2022-04-25 15:09 被阅读0次

    背景

    今天有一个孙组件需要部分数据的情况,因为子组件与父组件是之前同事已经写好了的。我不想增加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这个行为其实完全打乱了数据管理。

    相关文章

      网友评论

          本文标题:vue2中的provide与inject踩坑

          本文链接:https://www.haomeiwen.com/subject/cjwfyrtx.html