0

Using vuejs3 with composition api, I get data from an api asynchronously.

const accounts = ref([])
const credits = ref([])
const debits = ref([])
const summary = ref([])

const getaccounts = async () => {
  try {
    // getData is a preformatted axios function
    const response = await getData.get(`/myurl/${route.params.month}/${route.params.year}`)
    accounts.value = [...response.data.accounts]
    debits.value = [...response.data.accounts].filter(obj => {
      return obj.amount < 0
    })
    summary.value = [...debits.value] // DOESN'T WORK
    setSummary(summary.value) // THEREFORE ALSO DOESN'T WORK
    credits.value = [...response.data.comptes].filter(obj => {
       return obj.amount > 0
    })
  } catch (error) {
    console.log(error)
  }
}

debits.value is and Array with 55 objects that looks like so:

const data = [
  { id: 12, amount : 45, category: "alim" },
  { id: 15, amount : 32, category: "misc" },
  { id: 11, amount : 145, category: "bla" },
  { id: 20, amount : 40, category: "misc" },
  { id: 22, amount : 12, category: "alim" },
  { id: 33, amount : 5, category: "bla" }
]

I want to group total amounts per categorie in a new array of objects. Code works in plain javascript and this is what the function setSummary looks like:

const setSummary = (debs) => {

   let arr = debs.reduce((acc, item) => {
    let existItem = acc.find(({categorie}) => item.categorie === categorie);
    if(existItem) {
      existItem.amount += item.amount;
    } else {
      acc.push(item);
    }
    return acc;
  }, [])

  resume.value = arr
}

Any manipulation I do on summary.value affects debits.value. I know that Vue reactivity is based on Proxydocumentation but I don't see how to clone or deconstruct an object in such a manner that manipulations on the cloned object don't affect the "parent".

thiebo
  • 1,339
  • 1
  • 17
  • 37

1 Answers1

3

You need to deep-clone the array of objects. The array elements are reference values. So if you modify the elements in summary.value, it will affect on the elements in debits.value.

instead of

summary.value = [...debits.value]

try

summary.value = JSON.parse(JSON.stringify(debits.value))

or, use lodash

import { cloneDeep } from "lodash"
.....

summary.value = cloneDeep(debits.value)

Mitsuki
  • 58
  • 2
  • 6
  • 1
    Also it would be better using reactive instead of ref for arrays/objects. – Mitsuki Jun 01 '22 at 23:34
  • The answer is correct but the array elements actually are not references. [Is JavaScript a pass-by-reference or pass-by-value](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language) – Duannx Jun 02 '22 at 01:54
  • Thanks. I did both: `cloneDeep` and use `reactive`. Works as expected. – thiebo Jun 02 '22 at 04:52
  • @Duannx Sorry, I don't get what you mean... It's an array of objects, which means the array contains object references. – Mitsuki Jun 03 '22 at 03:57
  • I want to clarify that it's just a reference in case of the element is an object. If the elements are the primitive type like `number` or `string`, they are values, not references – Duannx Jun 03 '22 at 04:19