Use of $watch in Vue (solve rangeerror: maximum call stack size exceeded)

Problems encountered:

In a requirement, the change of a form needs a function of history recording. Because the form is very large (it is to edit an article), it is impossible to be specific to a certain attribute, so the method of watch monitoring is adopted, and {deep: true} is set. However, when previewing, I encountered the error of rangeerror: maximum call stack size exceeded . After some investigation, I found that it was caused by watch monitoring, and then I didn’t know what the problem was.

Even if nothing is written in the business code, a simple console.log will not work. As long as deep: true is set, an error will be reported, which is a headache. I didn’t find a similar case on the Internet. I thought again: since the error lies in the watch, can I dynamically monitor and cancel monitoring ?I found the answer on the official website -watch

Basic use of $watch (refer to the official website)

VM. $watch (exporfn, callback, [options]) the return value is a {function} unwatch , which returns a function to cancel the observation, which is used to stop the trigger callback option: deep, deep listening option: immediate, whether to execute once immediately

// Key Path
vm.$watch('a.b.c', function (newVal, oldVal) {
  // Do something

// function
var unwatch = vm.$watch(
  function () {
    // The expression `this.a + this.b` is called every time a different result is reached
    // the handler function will be called.
    // This is like listening for an undefined computed property
    return this.a + this.b
  function (newVal, oldVal) {
    // Do something

// Cancel the listener


My solution, for reference

// Call setWatchChapters when created, call removeWatchChapters in other cases, depending on the business case
export default {
	data () {
		return {
			unWatchChapters: null
		setWatchChapters () { // Setting up a listener for chapters
			if (!this.unWatchChapters) { // prevent setting listeners more than once
				setTimeout(() => { // There are still some bugs, so use setTimeout to add to the event queue
					this.unWatchChapters = this.$watch('report.chapters', () => {
						// do something
					}, { deep: true })
				}, 0)
    	removeWatchChapters () { // Unlisten to chapters
			if (this.unWatchChapters) {
				this.unWatchChapters = null

Read More: