Search code examples
javascriptvuejs3vue-componentreactive

Vue js 3 Reactivity confused with data change methods in component api


hi guys i have a quick question about changing the data in vue3 reactive data let me show you my code so you get what is the idea

const packageInfo = reactive({
    data:[]
})

this is my code sample data for package is like this

data =>
[
    {
       id:"ship_id"
       ship:"ship_number"
       products:
              [
                 {product:"product_name",id:"product_id"},
                 {product:"product_name2",id:"product_id2"}
              ]
    }
]

so basically I have two functions one for removing package with id and one for removing product with id my package function works perfectly and removes data also effects the UI I mean the change effects the component and removes data from table too

but for product delete with id I'm facing problems data gets deleted but its not effecting the component and UI this is my code

async function deletePackage(pack){
    let { data } = await axios.delete(`/packages/${pack.id}`);
    if(data == 1){
        packageInfo.data = packageInfo.data.filter(function( obj ) {
            return obj.id !== pack.id;
        });
    }
    
}
async function deleteProduct(pack,product){
    
    let tmData = packageInfo.data
    tmData[tmData.indexOf(pack)].products = tmData[tmData.indexOf(pack)].products.filter(function( obj ) {
            return obj.id !== product.id;
    });
    packageInfo.data = tmData
    // packageInfo.data[packageInfo.data.indexOf(pack)].products = packageInfo.data[packageInfo.data.indexOf(pack)].products.filter(function( obj ) {
    //         return obj.id !== product.id;
    // });
}

in second function I'm trying to remove the product with same id only not total package or total products

can you please tell me what am I doing wrong ?

EDIT:

Here is how I'm using packageInfo in UI

<ScannerTable :table-data="packageInfo"/>

And in ScannerTable Component

const props = defineProps({
    tableData:{
        default:[]
    }
})

I'm using this to get data everything works perfectly even the package removal works and updates in templates table but products removal not works !

EDIT 2: even when I changed the way of showing to show if show value is true only still its not effective am I missing something let me show you one image this first array of objects which is data is totally reactive but the second layer which is products is not reactive and changes are not effected in UI

enter image description here

EDIT 3

I Found out this way I can change the data and the products get deleted from the table so basically I'm changing the parent shipment of product and calling Tick which changes so basically product is not reactive but can someone explain me why ?! I'm getting so confused even I used ref() for my show but still not effective

packageInfo.data.forEach(async(dasdata,i)=>{
        if(dasdata.id == pack.id){
            packageInfo.data[i].show = false
            dasdata.products.forEach(async(prods,j)=>{
                if(prods.id == product.id){
                    packageInfo.data[i].products[j].show = false;
                }
            })
            await nextTick()
            packageInfo.data[i].show = true
        }
    })

Solution

  • Here is what I've done to simulate your issue.

    <template>
    <div>
      <ul v-for="pkg in packageInfo.data" :key="pkg.id">
      <li>
        {{ pkg.ship }}
        <span @click="removePackage(pkg)" style="color: red; cursor: pointer">X</span>
      </li>
      <ul v-for="prod in pkg.products" :key="prod.id">
        <li>
          {{ prod.product }}
          <span @click="removeProduct(pkg,prod)" style="color: red; cursor: pointer">X</span>
        </li>
      </ul>
    </ul>
    </div>
    </template>
    
    <script setup lang="ts">
    import { reactive } from 'vue';
    
    const packageInfo = reactive({
      data: [
        {
          id: 'ship_id1',
          ship: 'ship_number1',
          products:
            [
              { product: 'product_name1_1', id: 'product_id1' },
              { product: 'product_name1_2', id: 'product_id2' },
            ],
        },
        {
          id: 'ship_id2',
          ship: 'ship_number2',
          products:
            [
              { product: 'product_name2_1', id: 'product_id11' },
              { product: 'product_name2_2', id: 'product_id22' },
            ],
        },
      ],
    });
    
    function removePackage(pack: any) {
      packageInfo.data = packageInfo.data.filter(x => x.id !== pack.id);
    }
    
    function removeProduct(pack: any, product:any) {
      pack.products = pack.products.filter(x => x.id !== product.id);
      // let tmData = packageInfo.data
      // tmData[tmData.indexOf(pack)].products = tmData[tmData.indexOf(pack)].products.filter(function( obj ) {
      //   return obj.id !== product.id;
      // });
      // packageInfo.data = tmData
    }
    </script>
    

    I think your issue goes around passing props or there is something wrong with your rendering mechanism.

    I have another implementation (ScannerTable in a separate file), but that's not the case.