'Vue 3 how to rerender properly when prop value is updated
I have a Vue component to display a list of data. It should receive the data and sortBy as props and render correctly. However, I have an extra button in the component that I want to update sortBy and re-render the new list but I don't know how to assign new data to computed property sortedData. Thanks a lot if I can have some advices.
<template>
<div>
<template v-for="(item, index) in sortedData" :key="index">
{{ item.name }}
</template>
<button @click.prevent="sortWith('color')">sort Color</button>
</div>
</template>
<script>
export default {
props: {
data: {
type: Array,
default: []
},
sortBy: {
type: String,
default: 'name'
},
},
methods: {
sort(array, sortBy) {
return array.sort(function (a, b) {
return b[sortBy] - a[sortBy]
})
},
sortWith(sortBy) {
// Need to sort the list and re-render new order
}
}
computed: {
sortedData() {
return this.sort(this.data, this.sortBy)
}
}
}
</script>
Solution 1:[1]
Try like following snippet:
const app = Vue.createApp({
data() {
return {
items: [{name: 'aaa', color: 'red'}, {name: 'ccc', color: 'purple'}, {name: 'fff', color: 'yellow'}, {name: 'bbb', color: 'blue'}, {name: 'eee', color: 'green'}],
sortingBy: 'name',
sortingOrder: false
}
},
methods: {
setSorting(item) {
this.sortingBy = item
this.sortingOrder = !this.sortingOrder
}
}
})
app.component('child', {
template: `
<div>
<template v-for="(item, index) in sortedData" :key="index">
<div>{{ item.name }} - {{ item.color }}</div>
</template>
<div class="sort">
<p>Sort By (child) :</p>
<div v-for="(title, i) in Object.keys(data[0])" :key="i" class="fields">
<a href="#" @click="sorting(title)">{{ title }}</a>
</div>
</div>
</div>
`,
props: {
data: {
type: Array,
default: []
},
sortBy: {
type: String,
default: 'name'
},
sortOr: {
type: String,
default: false
},
},
data() {
return {
sortField: this.sortBy,
sortOrder: this.sortOr
}
},
methods: {
sort(array, sortBy) {
return array.sort((a, b) => {
let x = a[sortBy].toLowerCase()
let y = b[sortBy].toLowerCase()
if (this.sortOrder) {
return x > y ? -1 : 1;
} else {
return x > y ? 1 : -1;
}
return 0
})
},
sorting(item) {
this.sortField = item
this.sortOrder = !this.sortOrder
}
},
computed: {
sortedData() {
return this.sort(this.data, this.sortField)
}
},
watch: {
sortBy: function (val) {
this.sortField = val
},
sortOr: function (val) {
this.sortOrder = val
},
}
})
app.mount('#demo')
.sort {
display: flex;
align-items: center;
}
.fields {
margin-left: 1em;
}
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="demo">
<div class="sort">
<p>Sort By (parent) :</p>
<div v-for="(title, i) in Object.keys(items[0])" :key="i" class="fields">
<a href="#" @click="setSorting(title)">{{ title }}</a>
</div>
</div>
<child :data="items" :sort-by="sortingBy" :sort-or="sortingOrder"></child>
</div>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
