0

I've always thought that object.assign and spread operator are similar.

But today, I have an error 'You may have an infinite update loop in a component render'

State in advance, the structure of the parent object is like this:

the structure of the parent object

I tried the following three ways:

one: spread operator, got this error 'You may have an infinite update loop in a component render'

const template = { ...parent , path: '', noShowingChildren: true }
this.onlyOneChild = template

two: Deep Copy, got this error 'You may have an infinite update loop in a component render'

const template = JSON.parse(JSON.stringify(parent))
template.path = ''
template.noShowingChildren = true
this.onlyOneChild = template

three: Object.assign, works fine.

const template = Object.assign(parent, { path: '', noShowingChildren: true })
this.onlyOneChild = template

These three situations, the results make me feel very confused.

Can someone answer this question for me?

Here is the code.Thank you for your help.

    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
      <router-link
        v-if="onlyOneChild.meta"
        :to="resolvePath(onlyOneChild.path)"
      >
        <el-menu-item
          :index="getIndex(onlyOneChild.path)"
          :class="{'submenu-title-noDropdown':!isNest}"
        >
          <item
            v-if="onlyOneChild.meta"
            :icon="onlyOneChild.meta.icon||item.meta.icon"
            :title="onlyOneChild.meta.title"
          />
        </el-menu-item>
      </router-link>
    </template>
export default {
  name: 'SidebarItem',
  components: { Item, AppLink },
  props: {
    // route object
    item: {
      type: Object,
      required: true
    },
    isNest: {
      type: Boolean,
      default: false
    },
    basePath: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      onlyOneChild: null
    }
  },
  methods: {
    hasOneShowingChild (children, parent) {
      const showingChildren = children.filter(item => {
        // console.log(item)
        if (item.meta.hidden) {
          return false
        } else {
          // Temp set(will be used if only has one showing child)
          this.onlyOneChild = item
          return true
        }
      })
      // When there is only one child router, the child router is displayed by default
      if (showingChildren.length === 1) {
        return true
      }

      // Show parent if there are no child router to display
      if (showingChildren.length === 0) {
        console.log('this is parent object:', parent)
        // const template = { ...parent , path: '', noShowingChildren: true }
        // const template = { ...JSON.parse(JSON.stringify(parent)), path: '', noShowingChildren: true }
        // const template = JSON.parse(JSON.stringify(parent))
        // template.path = ''
        // template.noShowingChildren = true
        const template = Object.assign(parent, { path: '', noShowingChildren: true })
        this.onlyOneChild = template
        return true
      }

      return false
    }
  }
}
J.Kuai
  • 79
  • 1
  • 8
  • `JSON.parse(JSON.stringify(parent))` is never a good idea. There are [much better ways](https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript) to copy an object. – T.J. Crowder Oct 31 '21 at 17:47
  • 1
    Your `Object.assign` code is not the same as your spread code, you're updating the existing `parent` object in the `Object.assign` code but creating an entirely new object in the spread code. The equivalent `Object.assign` code would be `const template = Object.assign({}, parent, { path: '', noShowingChildren: true })`. Since with your `assign` you're not creating a new object, it's probably just hiding the actual problem. (I haven't done Angular in years, so I can't point to what the actual issue is.) – T.J. Crowder Oct 31 '21 at 17:49
  • @T.J.Crowder I tried `const template = Object.assign({}, parent, { path: '', noShowingChildren: true })`, indeed, the problem is not a deep copy of the problem, thank you for your help – J.Kuai Oct 31 '21 at 17:57
  • Neither spread nor `assign` is a deep copy. My comments were two separate comments. The deep copy part related to your JSON stringify/parse cycle (which is a deep -- but highly flawed and inefficient -- copy). – T.J. Crowder Nov 01 '21 at 07:07

1 Answers1

1

The first two methods you're using (parsing JSON and spreading) will create new objects or references, while the last method (assign) will use the exact same one and just assign new values to it. So I can only assume that the first two will trigger a state update by changing this.onlyOneChild completely, which will in return trigger another render, while the last one will not trigger a state change (since it's changing the values on that object and not the entire reference) and not trigger another rerender.