0

I'm trying to pass an array of object to a childComponent as prop but when I add an object in it, it doesn't render. (Note: I'm working on vuejs 2.6)

I suppose it has a link with the "monitoring" of the items of the array and not the array itself? Stuff is that if I do not pass the prop and use the default value instead, it's working perfectly. I think I'm missing something here. Could someone help me ?

By curiosity is this kind of behavior still stand with vue3js ?

As you can see below:

enter image description here

App.vue:

<template>
 <div id="app">
  <Card
   v-for="user in users"
   :key="user.userId"
   :userId="user.userId"
   :username="getUsernameFromUserId(user.userId)"
   :links="getUserLinksFromUserId(user.userId)"
  />
 </div>
</template>

<script>
import Card from "./components/Card.vue";

export default {
 name: "App",
 components: {
  Card,
 },
 data: function () {
  return {
   users: [
    { userId: 1, name: "Bob" },
    { userId: 2, name: "Alice" },
    { userId: 3, name: "Eliot" },
   ],
   links: [
    { userId: 1, link: "hello->world" },
    { userId: 1, link: "world->!" },
    { userId: 3, link: "hello->back" },
    { userId: 4, link: "hello->you" },
   ],
  };
 },
 methods: {
  getUsernameFromUserId: function (userId) {
   return this.users.filter((obj) => obj.userId == userId)?.[0]?.name ?? "Not found";
  },
  getUserLinksFromUserId: function (userId) {
   return this.links.filter((obj) => obj.userId == userId);
  },
 },
};
</script>

Card.vue

<template>
  <div class="card">
    <h1>{{ username }}</h1>
    <button @click="addLink">Add One link</button><br><br>
    <span v-if="links.length == 0">No links</span>
    <div class="links">
        <Link v-for="link in links" :key="links.indexOf(link)" :link="link"></Link>
    </div>
  </div>
</template>

<script>
import Link from '../components/Link'

export default {
  components:{Link},
  props: {
    userId: Number,
    username: String,
    links: { type: Array, default: () => [], required: false },
  },
  methods:{
    addLink: function(){
      this.links.push({
        userId: this.userId,
        link: 'newlink->cool'
      });
    }
  }
}
</script>

Link.vue

<template>
 <div>
  <span>UserId: {{ this.link.userId }} Link: {{ this.link.link }</span>
 </div>
</template>

<script>
export default {
 props: {
  link: { type: Object, default: () => [], required: false },
 },
};
</script>

1 Answer 1

1

This is a bad way to work with props

Note: do not focus on Dev Tools too much as it can be "buggy" at times - especially if you use Vue in a wrong way. Focus on your app output

  1. Your Card.vue component is modifying (push) a prop, which is not recommended but it sort of works if the prop is object/Array and you do not replace it, just modify it's content (as you do)
  2. But in your case, the values passed to props are actually generated by a method! The getUserLinksFromUserId method is generating a new array every time it is called, and this array is NOT reactive. So by pushing to it, your component will not re-render and what is worse, parent's links array is not changed at all! (on top of that - if App.vue ever re-renders, it will generate new arrays, pass it to pros and your modified arrys will be forgoten)

So intead of modifying links prop in Card.vue, just emit an event and do the modification in App.vue

Sign up to request clarification or add additional context in comments.

3 Comments

Oh Yes I see, in the end its better to move the getUserLinksFromUserId in the Card.vue. And If I need to add an item in the array I should emit an event from the child to ask the parent class to add it on top. Isn't ?
Regarding how to pass links, it is not that clear. You can pass all links to a Card and filter there (but instead of using method, computed would be more appropriate and more efficient)
Thank you for your answer, as I read clearly, I suppose that this would happened as well with vue3js

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.