Vue.js infinite loop on component re-render [closed]

Tags: , , ,



I’m trying to build tables based off a few selected properties from a previous component: I’m rendering a component called ‘branch-comparison‘ to compare XML files and their properties and values. This component takes in two props:

selectedEnvs: An array of objects with a name and object

commonFiles: An array of files with a name and object

I’m using vue-tables-2 to build these tables. At the top of the template it runs a function called getProps() to generate a set of all possible properties from each file. I’ve hard coded 0 because currently I’m only letting the user choose 1 file at a time. It then goes through each file (only 1) and gets data for the main table and the comparison tables. They are virtually the same function (getHeadData and getTableData) but I’ve seperated them for now for further customization. The code is not that important for actually generating the tables, however something inside of them is causing my code to go in an infinite loop.

On the initial render of the component, there is never an infinite loop. Everything runs through, and doesn’t break at all and works wonderfully. Once however the component has been rendered, and I make a change to the props, or even simply save the file in the editor and vue-cli hot reloads it, it goes into and infinite loop. All the data still get’s generate fine and the component does as it’s supposed to. But it loops through 101 times no matter what.

Things I’ve looked into:

Changing the data: I fully understand a component re renders on data change… however I don’t believe I am changing any reactive data in any method call. I’m simply declaring it locally inside the function and returning it to that temporary variable. Also if this was the case, I believe it would go into an infinite loop on the initial component load, but this is not the case. It goes into the infinite loop only on a refresh or prop change.

Mutating the Vuex state: I looked into this but I am never changing the state of anything. I am simply accessing it in the getTableData and getHeadData methods. I then thought, perhaps assigning a variable to point to this state object is causing it to re render based on something accessing the state, so I tried instead of

this.$store.state.branchesToCompare[branchIdx].obj[env.name].app_config[this.commonFiles[fileIdx]].forEach(envProp
=> {

to use

var x = JSON.parse(JSON.stringify(this.$store.state.branchesToCompare[branchIdx].obj[env.name].app_config[this.commonFiles[fileIdx]])

then

x.forEach(envProp =>

but this still does not work.

If I comment out the code that calls getHeadData() and getTableData() it loops through the appropriate amount of times.

Here is the code.. I am still new to Vue so any more general suggestions I am more than open to:

 <template>
   <div id="BranchComparison">
      <div :set="info = getProps(0)">
         <div class="file" v-for="(file, fileIdx) in commonFiles" :key="(file, fileIdx)">
            <h3>{{ file }} </h3>
            <b-row :set="mainTable = getHeadData(fileIdx, info.props, info.columns)">
               <b-col class="mainBranch">
                  <h5 class="fileName"> {{ $store.state.branchSelection.split('.').slice(0, -1).join('.') }} <span style="font-size: 14px;">vs </span> </h5>
                  <v-client-table
                     :data="mainTable.data"
                     :columns="mainTable.columns"
                     :options="mainTableOptions"
                     size="small"
                  ></v-client-table>
               </b-col>
               <b-col class="compareBranch" v-for="(branch, branchIdx) in $store.state.branchesToCompare" :key="(branch, branchIdx)">  
                  <h5> {{ branch.name.split('.').slice(0, -1).join('.') }} </h5>
                  <v-client-table
                     :set="temp = getTableData(fileIdx, branchIdx, info.props, info.columns, mainTable)"
                     :data="temp.data"
                     :columns="temp.columns"
                     :options="temp.options"
                     size="small"
                  ></v-client-table>
               </b-col>
            </b-row>
         </div>
      </div>
   </div>
</template>

<script>

export default {

   props: ['selectedEnvs', 'commonFiles'],

   data(){
      return{
         mainTableOptions:{
            filterable: false,
            filterByColumn: false,
            perPage: 200,
            pagination: {
               show: false,
               dropdown: false
            },
            sortable: [''],
            resizableColumns: false,
         },
      }  
   },

   methods: {
      getTableData(fileIdx, branchIdx, props, columns, mainTable){

         var data = []

         var compareTableOptions = {
            filterable: false,
            perPage: 200,
            pagination: {
               show: false,
            },
            sortable: [''],
            hiddenColumns: ['Property'],
            resizableColumns: false,
            cellClasses: {}
         }


         props.forEach(prop => {
            var temp = { Property: prop }
            this.selectedEnvs.forEach(env => {
               var found = false;
               this.$store.state.branchesToCompare[branchIdx].obj[env.name].app_config[this.commonFiles[fileIdx]].forEach(envProp => {
                  if(envProp){
                     if (prop == envProp["@name"]) {
                        compareTableOptions.cellClasses[env.name] = []
                        compareTableOptions.cellClasses[env.name].push({
                           class: 'same',
                           condition: row => {
                              try{
                                 return row[env.name] == mainTable.data[i][env.name]
                              } catch{
                                 console.log('This is a different problem ')
                              }
                           }
                        })
                        found = true;
                        temp[env.name] = envProp["@value"]
                     }
                  }
               });
               if (!found){
                  temp[env.name] = 'Not found'
               } 
            })
            data.push(temp)
         });

         return {
            columns: columns,
            data: data,
            options: compareTableOptions
         }
      },

      getHeadData(fileIdx, props, columns){
         var data = []
         props.forEach(prop => {
            var temp = { Property: prop }
            this.selectedEnvs.forEach(env => {
               var found = false;
               this.$store.state.jsonObject[env.name].app_config[this.commonFiles[fileIdx]].forEach(envProp => {
                  if(envProp){
                     if (prop == envProp["@name"]) {
                        found = true;
                        temp[env.name] = envProp["@value"]
                     }
                  }
               });
               if (!found){
                  temp[env.name] = 'Not found'
               } 
            })
            data.push(temp)
         });

         return {
            columns: columns,
            data: data
         }
      },

      getProps(fileIdx){

         if(this.commonFiles.length == 0) return

         var columns = ['Property']
         var props = new Set()

         this.selectedEnvs.forEach((env, idx) => {
            columns.push(env.name)
            this.$store.state.branchesToCompare.forEach(branch => {
               branch.obj[env.name].app_config[this.commonFiles[fileIdx]].forEach(prop => {
                  if(prop){
                     props.add(prop["@name"])
                  }
               })
            });
            this.$store.state.jsonObject[env.name].app_config[this.commonFiles[fileIdx]].forEach(prop => {
               if(prop){
                  props.add(prop["@name"]);
               }
            });
         });

         var ret = { props: props, columns: columns }

         return ret;
      }
   }
}

</script>

What it produces

Answer

I’ve solved it. The code above is actually fine. Shortly before I posted the code, I was using a computed property in the v-for AND in the getHeadData(), what I think was happening was it was a nested computed property, and on the inner loop it recomputed it and then tried the outer loop again, and so forth. I’m still puzzled why it work on the initial render, but oh well. It is working now.



Source: stackoverflow