Error in nextTick: “TypeError: Converting circular structure to JSON

created at 08-12-2021 views: 10

error message

[Vue warn]: Error in nextTick: "TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Vue'
    |     property '$options' -> object with constructor 'Object'
    |     property 'router' -> object with constructor 'VueRouter'
    --- property 'app' closes the circle"

Generally, error TypeError: Converting circular structure to JSON is because there is a circular reference, and the JSON.stringify method is used to convert it into a string

Case

// problem code
const x = {a: 8 };
const b = {x };
b.y = b; // circular reference
JSON.stringify(b); // Trigger an error

// solve the problem code
const x = {a: 8 };
const b = {x };
b.y = JSON.parse(JSON.stringify(b)); // Implicit deep copy, mainly to realize deep copy and remove circular references
JSON.stringify(b);

// You can also directly remove the circular reference code without using deep copy. The key point of the problem is to remove the circular reference

You cannot explicitly see the circular reference in the error location, because the code of the circular reference is implemented by the Vue framework code itself, so it is more difficult to find the place where the problem occurs.

cause of the problem

  • The router instance (this.$route obtained in the component) is stored in the state management state in vuex, and there is a circular reference
  • vuex uses the plugin vuex-persistedstate
  • With circular references in the state, the plugin vuex-persistedstate needs to execute JSON.stringify to convert the state data into a string and store it in the browser's local storage.
  • The next step is to solve it, that is, to remove the circular reference. The way to remove it is to make a deep copy of this.$route obtained in the component, and then store it in the state

use vuex to store information of route

attachment for reference

/**
 * get data type
 * @param {All} [o] data needs to be tested
 * @returns {String}
 */
export function getType(o){
  return Object.prototype.toString.call(o).slice(8,-1);
}

/**
 * Determine whether it is a specified data type
 * @param {All} [o] Data to be tested
 * @param {String} [type] type of data
 * @returns {Boolean}
 */
export function isKeyType(o, type) {
    return getType(o).toLowerCase() === type.toLowerCase();
}

/**
 * Deep copy, support common types object Date Array and other reference types
 * @param {Any} sth
 * @return {Any}
 */
export function deepClone(sth) {
  let copy;
  if (null == sth || "object" != typeof sth) return sth;
  if (isKeyType(sth, 'date')) {
    copy = new Date();
    copy.setTime(sth.getTime());
    return copy;
  }
  if (isKeyType(sth, 'array')) {
    copy = [];
    for (let i = 0, len = sth.length; i < len; i++) {
      copy[i] = deepClone(sth[i]);
    }
    return copy;
  }
  if (isKeyType(sth, 'object')) {
    copy = {};
    for (let attr in sth) {
      if (sth.hasOwnProperty(attr)) copy[attr] = deepClone(sth[attr]);
    }
    return copy;
  }
  return null;
}
created at:08-12-2021
edited at: 08-12-2021: