I'm struggling to figure out how to make properties of an array reactive. Is this possible? In the example below, the filteredResults array itself is reactive, and working, but neither the resultCountRef (wrapped in reactive()) nor the resultCount fields are reactive. In otherwords, if I click the Filter for Apples button, the filteredResults changes to just the one item, but the two count fields remain at 3. Note that using {{filteredResults.length}} in the template does work as expected. Here is a working sample.
And here is the code (a Search.vue composition API component, and a useFilter composition function):
Search.vue:
<template>
<div>resultCountRef: {{resultCountRef}}</div>
<div>resultCount: {{resultCount}}</div>
<div>filteredResults.length: {{filteredResults.length}}</div>
<div>filteredResults: {{filteredResults}}</div>
<div>filters: {{filters}}</div>
<div><button @click="search()">Search</button></div>
<div><button @click="applyFilter('apples')">Filter for Apples</button></div>
</template>
<script>
import { reactive } from 'vue';
import useFilters from './useFilters.js';
export default {
setup(props) {
const products = reactive(['apples', 'oranges', 'grapes']);
const { filters, applyFilter, filteredResults } = useFilters(products);
const resultCountRef = reactive(filteredResults.value.length);
const resultCount = filteredResults.value.length;
return {
resultCountRef,
resultCount,
filteredResults,
filters,
applyFilter,
};
},
};
</script>
useFilters.js:
import { ref, onMounted } from 'vue';
function filterResults(products, filters) {
return products.filter((product) => filters.every(
(filter) => {
return product.includes(filter);
},
));
}
export default function useFilters(products) {
const filters = ref([]);
const filteredResults = ref([...products]);
const applyFilter = (filter) => {
filters.value.push(filter);
filteredResults.value.splice(0);
filteredResults.value.splice(0, 0, ...filterResults(products, filters.value));
};
return { filters, applyFilter, filteredResults };
}