admin管理员组

文章数量:1296895

I am trying to get my head wrap around how props are passed to child ponents and how they are updated from there.

// parent.vue
<template>
    <div>
        <div v-for="elem in getCurrentArray">
            <child-ponent :elem="elem"></child-ponent>
        </div>
        <button @click.prevent="currentIdx--">Prev</button>
        <button @click.prevent="currentIdx++">Next</button>
    </div>
</template>
<script>
    export default {
        ponents : {
            ChildComponent
        },
        data(){
            return {
                arr : [ ["A", "B", "C" ], [ "D", "E" ]], // this would be populated from vue store
                currentIdx : 0
            }
        },
        puted : {
            getCurrentArray(){
                return this.arr[this.currentIdx]
            }
        },
    }
</script>
// child.vue
<template>
    <div>Prop: {{elem}} <input type="text" v-model="myinput" @blur="save" /></div>
</template>
<script>
    export default {
        props : [ "elem" ],
        data(){
            return {
                myinput : this.elem
            }
        },
        methods : {
            save(){
               // this.$store.dispatch("saveChildElement", { myinput }
            }
        },
        mounted(){ console.log( this.elem + " being rendered" ) }
    }
</script>

In this example, I have two sets of arrays ['A','B','C'] and ['D','E']. On page load, the first set is rendered thru child ponents.

Looks good. However, when I click next to go to the second set, I get this:

So, while the props are being passed correctly, the textbox input values are not updated. When I checked the console.log, it's clear that vue does not re-render child ponents for "D" and "E". Instead, it simply uses the existing ponents for "A" and "B".

Is there a way to force vue to re-render the ponents? If not, how can I make sure that the textbox input gets the latest prop values? Keep in mind that I want to be able to save changes to the input values via vue store.

I am trying to get my head wrap around how props are passed to child ponents and how they are updated from there.

// parent.vue
<template>
    <div>
        <div v-for="elem in getCurrentArray">
            <child-ponent :elem="elem"></child-ponent>
        </div>
        <button @click.prevent="currentIdx--">Prev</button>
        <button @click.prevent="currentIdx++">Next</button>
    </div>
</template>
<script>
    export default {
        ponents : {
            ChildComponent
        },
        data(){
            return {
                arr : [ ["A", "B", "C" ], [ "D", "E" ]], // this would be populated from vue store
                currentIdx : 0
            }
        },
        puted : {
            getCurrentArray(){
                return this.arr[this.currentIdx]
            }
        },
    }
</script>
// child.vue
<template>
    <div>Prop: {{elem}} <input type="text" v-model="myinput" @blur="save" /></div>
</template>
<script>
    export default {
        props : [ "elem" ],
        data(){
            return {
                myinput : this.elem
            }
        },
        methods : {
            save(){
               // this.$store.dispatch("saveChildElement", { myinput }
            }
        },
        mounted(){ console.log( this.elem + " being rendered" ) }
    }
</script>

In this example, I have two sets of arrays ['A','B','C'] and ['D','E']. On page load, the first set is rendered thru child ponents.

Looks good. However, when I click next to go to the second set, I get this:

So, while the props are being passed correctly, the textbox input values are not updated. When I checked the console.log, it's clear that vue does not re-render child ponents for "D" and "E". Instead, it simply uses the existing ponents for "A" and "B".

Is there a way to force vue to re-render the ponents? If not, how can I make sure that the textbox input gets the latest prop values? Keep in mind that I want to be able to save changes to the input values via vue store.

Share asked Sep 22, 2019 at 15:28 user3628119user3628119 3575 silver badges15 bronze badges 2
  • Yes, looks like a duplicate. However, that post is missing the sample code (broken link), so it may not be as useful – user3628119 Commented Sep 23, 2019 at 3:39
  • My bad, pletely missed that. Thanks. – yuriy636 Commented Sep 23, 2019 at 20:35
Add a ment  | 

4 Answers 4

Reset to default 3

Add a key as cool-man says, it will fix the issue.

However, your check for ponent re-rendering is flawed, you used the child mounted life cycle, and because you see it running only once you think the ponent isn't re-rendering. But this is wrong. "mounted" happens only once in a ponent life cycle, and because you're using the same ponent for ['A','B','C'] and then for ['D','E'] vue knows not to re-create the ponents and simply re-renders them with the new props.

Try to add the :Key prop in the v-for loop

<div v-for="elem in getCurrentArray" :key="elem">

To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item:

... List Rendering - Maintaining State

Keys must be unique, if you have two or more same value in your array, for example ['A',' B', 'A'] it will create a conflict, the best way to overe this is to add a generated unique 'ID' for each instance.

Or In alternative (a short term solution)

You can use the loop index in bination with the array value, this should give you a more or less unique key.

<div v-for="(elem, index) in getCurrentArray" :key="elem + index">

You can ask your ponent to re-render. (The other answers of updating the key is correct).

However, if you do want to use Vuex to manage state, I suggest you do that first as there is (essentially) a different mechanism that will do that re-render for you, and feel much easier. Namely the “puted properties” will likely solve that for you.

I remember getting stuck on this when I was starting out, and once I implemented Vuex I wished I had just done it that way, which kind of just solved the problem for me as part of its workflow. (It will likely mean you don’t need to update key, but you have that in case you have a plex situation when you still need to force a re-render).

Edit: As @JonyB rightly pointed out, you are trying to re-render the whole ponent. If you think about it, what you really want to do here is not re-render the whole ponent, but merely update the state. Therefore, once you implement Vuex, it will likely solve this for you as it allows you to deal with state separately.

All you need to add the key to the v-for loop and it will work.

Replace

<div v-for="elem in getCurrentArray">

with

<div v-for="elem in getCurrentArray" :key="elem">

Ref: https://v2.vuejs/v2/guide/list.html#v-for-with-a-Component

本文标签: javascriptVuejs child components are not being rerenderedStack Overflow