[Vuejs]-Why I'm Facing the error [Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"

0👍

This is happening because <p> is being rendered while product is still an empty object (product: {}).

You could use v-if to render only if product already has been loaded.

<template>
  <p v-if="dataLoaded">Sold By: {{ product.user.name }}</p>
</template>
<script>
export default {
  data() {
    return {
      product: {},
      dataLoaded: false,
    };
  },

  methods: {
    loadData() {
      axios.get("/api/" + this.$route.params.slug + "/product").then(
        (response) => {
          this.product = response.data;
          this.dataLoaded = true;
        },
        () => {}
      );
    },
  },

  created() {
    this.$Progress.start();
    this.loadData();
    this.$Progress.finish();
  },
};
</script>

1👍

The error is self-explanatory: you’re using {{product.user.name}} in the template. But before the product has returned from BE, product.user is undefined and therefore does not have a .name property.

The simplest fix would be to place a v-if on the <p>:

<p v-if="product.user">Sold By: {{product.user.name}}</p>

Another generic solution for this type of problem is to use a computed:

<template>
  <p>Sold By: {{productUserName}}</p>
</template>
<script>
export default {
  // ...
  computed: {
    productUserName() {
      return this.product.user?.name || '';
    }
  }
  // ...
}
</script>

You can read more about optional chaining operator (used above) (?.) here.
Because it’s a fairly new addition to JavaScript, Vue doesn’t currently support it in <template> tags (but it works in <script>).


Additional note: a common mistake is to add an additional data member instead of using the source of the error (product.user in this case) either directly or through a computed. This creates two problems:

  • it decouples product.user from rendering the <p>. Which means that if BE returns a product without a user, you’ll still get the error, because you’ve set dataLoaded to true but the template still tries to read the property .name of user, which is falsy and therefore does not have a .name.
  • you create unnecessary boilerplate: anyone trying to understand or modify your code at a later time has to figure out the arbitrary connection between dataLoaded and product.user.

One of the reasons Vue is loved for is because it doesn’t require boilerplate code, unlike other frameworks (i.e: Angular). Keep it that way! By using v-if="product.user" in the template, someone reading that code will immediately understand the rendering logic, without having to look at the component code. Decreasing the time needed to figure out the code on a regular basis will greatly decrease the time needed to modify it, should you (or someone else) ever need to. This results into more flexible, more scalable code. Less bugs, less time spent => more money.

Leave a comment