chore: include component info in recursive update warning

This commit is contained in:
Evan You 2021-04-21 15:20:15 -04:00
parent 1b8f14ee76
commit 66b6b4226b
2 changed files with 25 additions and 6 deletions

View File

@ -1599,6 +1599,11 @@ function baseCreateRenderer(
} }
} }
}, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions) }, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions)
if (__DEV__) {
// @ts-ignore
instance.update.ownerInstance = instance
}
} }
const updateComponentPreRender = ( const updateComponentPreRender = (

View File

@ -1,6 +1,8 @@
import { ErrorCodes, callWithErrorHandling } from './errorHandling' import { ErrorCodes, callWithErrorHandling } from './errorHandling'
import { isArray } from '@vue/shared' import { isArray } from '@vue/shared'
import { ComponentPublicInstance } from './componentPublicInstance' import { ComponentPublicInstance } from './componentPublicInstance'
import { ComponentInternalInstance, getComponentName } from './component'
import { warn } from './warning'
export interface SchedulerJob { export interface SchedulerJob {
(): void (): void
@ -22,6 +24,7 @@ export interface SchedulerJob {
* stabilizes (#1727). * stabilizes (#1727).
*/ */
allowRecurse?: boolean allowRecurse?: boolean
ownerInstance?: ComponentInternalInstance
} }
export type SchedulerCb = Function & { id?: number } export type SchedulerCb = Function & { id?: number }
@ -164,8 +167,11 @@ export function flushPreFlushCbs(
preFlushIndex < activePreFlushCbs.length; preFlushIndex < activePreFlushCbs.length;
preFlushIndex++ preFlushIndex++
) { ) {
if (__DEV__) { if (
__DEV__ &&
checkRecursiveUpdates(seen!, activePreFlushCbs[preFlushIndex]) checkRecursiveUpdates(seen!, activePreFlushCbs[preFlushIndex])
) {
continue
} }
activePreFlushCbs[preFlushIndex]() activePreFlushCbs[preFlushIndex]()
} }
@ -200,8 +206,11 @@ export function flushPostFlushCbs(seen?: CountMap) {
postFlushIndex < activePostFlushCbs.length; postFlushIndex < activePostFlushCbs.length;
postFlushIndex++ postFlushIndex++
) { ) {
if (__DEV__) { if (
__DEV__ &&
checkRecursiveUpdates(seen!, activePostFlushCbs[postFlushIndex]) checkRecursiveUpdates(seen!, activePostFlushCbs[postFlushIndex])
) {
continue
} }
activePostFlushCbs[postFlushIndex]() activePostFlushCbs[postFlushIndex]()
} }
@ -235,8 +244,8 @@ function flushJobs(seen?: CountMap) {
for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {
const job = queue[flushIndex] const job = queue[flushIndex]
if (job) { if (job) {
if (__DEV__) { if (__DEV__ && checkRecursiveUpdates(seen!, job)) {
checkRecursiveUpdates(seen!, job) continue
} }
callWithErrorHandling(job, null, ErrorCodes.SCHEDULER) callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)
} }
@ -263,13 +272,18 @@ function checkRecursiveUpdates(seen: CountMap, fn: SchedulerJob | SchedulerCb) {
} else { } else {
const count = seen.get(fn)! const count = seen.get(fn)!
if (count > RECURSION_LIMIT) { if (count > RECURSION_LIMIT) {
throw new Error( const instance = (fn as SchedulerJob).ownerInstance
`Maximum recursive updates exceeded. ` + const componentName = instance && getComponentName(instance.type)
warn(
`Maximum recursive updates exceeded${
componentName ? ` in component <${componentName}>` : ``
}. ` +
`This means you have a reactive effect that is mutating its own ` + `This means you have a reactive effect that is mutating its own ` +
`dependencies and thus recursively triggering itself. Possible sources ` + `dependencies and thus recursively triggering itself. Possible sources ` +
`include component template, render function, updated hook or ` + `include component template, render function, updated hook or ` +
`watcher source function.` `watcher source function.`
) )
return true
} else { } else {
seen.set(fn, count + 1) seen.set(fn, count + 1)
} }