简体   繁体   中英

Vue - Nested component won't update its data and re-render

Here is the scenario. I can upload one LiteratureReview and each can contain one or many Quote . So what I have are LiteratureReview (Parent) and Quote (Child) components. I get and post data using Axios. My backend is Laravel.

The LiteratureReview and Quote get their data from the app instance. After sending a post request, LiteratureReview would update and re-render the page. But when I want to add a Quote to its literature review, it does not update, I need to refresh the page.

app.js (or main.js)

export const app = new Vue({
    el: '#app',

    data: function () {
        return {
            literatureReviews: [],
            quotes: [],
        }
    },
    mounted() {
        axios.all([
            axios.get('/literature-review'),
            axios.get('/quote')
        ]).then(axios.spread((first_response, second_response) => {
            this.literatureReviews = first_response.data
            this.quotes = second_response.data
        }))
    }
});

index.blade.php

<literature-review v-for="(literatureReview, index) in literatureReviews" v-bind:loop="index + 1"
            v-bind:key="literatureReview.id" v-bind:literature_review_id="literatureReview.id"
            v-bind:topic="literatureReview.topic" v-bind:type="literatureReview.type"
            v-bind:year="literatureReview.year" v-bind:link="literatureReview.link"></literature-review>

LiteratureReview (Component; Parent)

<template>
    <div class="literature-card mb-5 rounded">
        .
        .
        .
        <quote v-for="quote in filterByLiteratureReview(quotes, literature_review_id)" v-bind:key="quote.id"
            v-bind:literature_review_id="literature_review_id" v-bind:quote="quote.quote" v-bind:page="quote.page"></quote>
    </div>
</template>

<script>
    import { app } from '../app.js'
    import { store } from '../app.js'

    export default {
        props: ['loop', 'literature_review_id', 'topic', 'type', 'year', 'link'],
        data() {
            return {
                quotes: app.quotes,
                sharedObject: store,
            }
        },
        methods: {
            filterByLiteratureReview(quotes, literature_review_id) {
                return this.quotes.filter(quote => quote.literature_review_id == literature_review_id)
            },
            updateLitIdForAddingQuote(value) {
                this.sharedObject.setLiteratureReviewIdAction(value)
            },
        }
    }
</script>

Quote (Component; Child)

<template>
    <div>
        <div class="row no-gutters px-3 pt-3">
            <div class="col" style="white-space: pre-wrap;">{{ quote }}</div>
        </div>
        <div class="row no-gutters" style="border-bottom: solid black 2px;">
            <div class="col py-4 pr-3 text-right">Pg {{ page }}</div>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['id', 'literature_review_id', 'quote', 'page'],
    }
</script>

Axios posting a Literature Review

axios.post('/literature-review', {
    topic: this.topic,
    type: this.type,
    year: this.year,
    link: this.link,
}).then( response => {
    $('#addSourceModal').modal('hide')
}).finally(
    axios.get('/literature-review').then(response => app.literatureReviews = response.data)
)

Axios posting a Quote

axios.post('/quote', {
    literature_review_id: this.sharedObject.state.literature_review_id,
    quote: this.quote,
    page: this.page
}).then( response => {
    console.log(response)
    $('#addQuoteModal').modal('hide')
    // location.reload();
}).finally(
    axios.get('/quote').then(response => app.quotes = response.data)
)

This article somewhat helped me solve it. So basically, data is updated from the popup modal's submit button. I made this button to emit an event to the root this.$root.$emit('forceRerender') which is received by LiteratureReview , this.$root.$on('forceRerender', this.forceRerender) on created. LiteratureReview component then runs its forceRerender() containing axios.get('/quote').then(response => this.quotes = response.data) .

Modal

<script>
    export default {
        props: ['target'],
        methods: {
            submit() {
                this.$emit('submit')
                this.$root.$emit('forceRerender')
            }
        }
    }
</script>

Literature Review Component

<script>
    import {
        app
    } from '../app.js'
    import {
        store
    } from '../app.js'

    export default {
        props: ['loop', 'literature_review_id', 'topic', 'type', 'year', 'link'],
        data() {
            return {
                quotes: app.quotes,
                sharedObject: store,
            }
        },
        created() {
            this.$root.$on('forceRerender', this.forceRerender)
        },
        methods: {
            filterByLiteratureReview(quotes, literature_review_id) {
                return this.quotes.filter(quote => quote.literature_review_id == literature_review_id)
            },
            updateLitIdForAddingQuote(value) {
                this.sharedObject.setLiteratureReviewIdAction(value)
            },
            forceRerender() {
                axios.get('/quote').then(response => this.quotes = response.data)
            }
        }
    }
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM