vue2中的provide与inject踩坑

2022-04-25  本文已影响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这个行为其实完全打乱了数据管理。

上一篇 下一篇

猜你喜欢

热点阅读