Ver código fonte

fix(provide): warn when using `provide` after mounting (#13954)

close #13921
close #13924
skirtle 5 meses atrás
pai
commit
247b2c2067

+ 43 - 0
packages/runtime-core/__tests__/apiInject.spec.ts

@@ -6,6 +6,7 @@ import {
   hasInjectionContext,
   inject,
   nextTick,
+  onMounted,
   provide,
   reactive,
   readonly,
@@ -372,4 +373,46 @@ describe('api: provide/inject', () => {
       })
     })
   })
+
+  describe('warnings for incorrect usage', () => {
+    it('should warn when inject() is called outside setup', () => {
+      inject('foo', 'bar')
+      expect(`inject() can only be used`).toHaveBeenWarned()
+    })
+
+    it('should warn when provide() is called outside setup', () => {
+      provide('foo', 'bar')
+      expect(`provide() can only be used`).toHaveBeenWarned()
+    })
+
+    it('should warn when provide() is called from a render function', () => {
+      const Provider = {
+        setup() {
+          return () => {
+            provide('foo', 'bar')
+          }
+        },
+      }
+
+      const root = nodeOps.createElement('div')
+      render(h(Provider), root)
+      expect(`provide() can only be used`).toHaveBeenWarned()
+    })
+
+    it('should warn when provide() is called from onMounted', () => {
+      const Provider = {
+        setup() {
+          onMounted(() => {
+            provide('foo', 'bar')
+          })
+
+          return () => null
+        },
+      }
+
+      const root = nodeOps.createElement('div')
+      render(h(Provider), root)
+      expect(`provide() can only be used`).toHaveBeenWarned()
+    })
+  })
 })

+ 4 - 3
packages/runtime-core/src/apiInject.ts

@@ -11,11 +11,12 @@ export function provide<T, K = InjectionKey<T> | string | number>(
   key: K,
   value: K extends InjectionKey<infer V> ? V : T,
 ): void {
-  if (!currentInstance) {
-    if (__DEV__) {
+  if (__DEV__) {
+    if (!currentInstance || currentInstance.isMounted) {
       warn(`provide() can only be used inside setup().`)
     }
-  } else {
+  }
+  if (currentInstance) {
     let provides = currentInstance.provides
     // by default an instance inherits its parent's provides object
     // but when it needs to provide values of its own, it creates its