Search code examples
vue.jsvue-composition-apivue-options-api

I keep getting "maximum recursive updates exceeded" in Vue when using axios and v-for


I am building an ecommerce site, and I created a component for product-card. I imported that component into the home page so I can display a list of products. I declare a variable of products in the data(){} and also create a beforeMount and put my logic inside it to fetch data using axios.

<template>
  <div>
      <section class="new__products"> 
      <div class="container">
        <div class="inner-new-products">
          <home-page-title title-text="New products"></home-page-title>
          <div class="product-cards">
            <product-card
              v-for="(product, index) in products"
              :key="index"
              :product-id="product._id"
              :old-price="product.old_price"
              :new-price="product.new_price"
              :product-image="product.product_image.reverse()[0].url"
              :product-desc="product.product_description"
              :product-name="product.product_name"
            ></product-card>
          </div>
          <!-- :product-link="product.productLink" -->
        </div>
      </div>
    </section>
  </div>
</template>
<script lang="ts">
export default defineComponent({
  name: "Home",
  components: { ProductCard },
  data() {
     let products: { productId: string, productImage: string, productDesc: string, 
                     newPrice: number, oldPrice: number }[] = [];
     return { products };
  },
  async beforeMount () {
     console.log('Fetching.... ');
     try {
       let response = await net.http.get('/product?page=1&size=7');
       this.products = response.data.message;
     } catch (error) {
       console.log("ERROR: " + error);
     }
  }
});
</script>

Everytime I load up the page I keep getting the error:

Uncaught (in promise) Error: Maximum recursive updates exceeded. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

When I deployed the code to production server, it just crashes as I load the page up. The whole site crashes due to this error, i'm devastated and don't know what to do.


Solution

  • The main problem is using Array.reverse in template.

    Reverse()

    The reverse method transposes the elements of the calling array object in place, mutating the array, and returning a reference to the array.

    So whenever the template renders, products array (it's elements rather) is changed which triggers another render etc.

    Also as the template can (and usually will) be rendered multiple times, applying reverse multiple times is probably not what you want.

    This types of operations (transforming source data into something to render) are better placed in computed (see example bellow - use productsView in the template instead of products)

    Also do not use index as :key. You seem to have _id which is probably unique so use it as key instead...

    export default defineComponent({
      name: "Home",
      components: { ProductCard },
      data() {
         let products: { productId: string, productImage: string, productDesc: string, 
                         newPrice: number, oldPrice: number }[] = [];
         return { products };
      },
      computed: {
        productsView() {
          return this.products.map(p => ({
            // copy all product properties and add product_image_url
            ...p,
            product_image_url: p.product_image.reverse()[0].url
          }))
        },
      },
      async beforeMount () {
         console.log('Fetching.... ');
         try {
           let response = await net.http.get('/product?page=1&size=7');
           this.products = response.data.message;
         } catch (error) {
           console.log("ERROR: " + error);
         }
      }
    });