Home » vue » You may have an infinite update loop in a component render function even with spread operator, but Object.assign works well

You may have an infinite update loop in a component render function even with spread operator, but Object.assign works well

Posted by: admin November 26, 2021 Leave a comment

Questions:

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
    }
  }
}
Answers:

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.