Home > OS >  Vue3 Ref,Reactivity not showing or updating
Vue3 Ref,Reactivity not showing or updating

Time:09-20

I'm trying to understand how ref/reactivity in Vue3 works. Due to some work related issues we are not using any state management libraries.

The idea is to increase and decrease the number of objects in an array and be able to edit what is in the array. But the view is not showing when I use reactive. It shows up when i use ref([]) but doesn't update number of rows.

Appreciate any feedback thanks.

list component:

<template>
  <div>
    <p>Where's My Items</p>
    
    <q-virtual-scroll
    id="parent-scroll"
    
    style="height: calc(100vh - 285px);"
    :items-size="items.length"
    :items-fn="getSnippets"
    :virtual-scroll-slice-size="5"
    scroll-target="#parent-scroll"
    ref="items"
    v-slot="{ item, index }">
    <q-item :key="item.id" dense >
      {{ item.id }} - {{ item.d }}-{{index}}
      <ParentItem :parentItem='item'></ParentItem>
    </q-item>

  </q-virtual-scroll>

    <p>Count: {{ items.length }} </p>
  </div>
</template>
<script lang='ts'>
import { defineComponent,  onMounted, watch, reactive } from 'vue';

// import {store} from 'src/controls/store';
// import {controller} from '../controls/control';
import {plane}  from '../controls/control';
// import controller from '../controls/store';
import { parentStruct, testStruct } from '../controls/types';
import ParentItem from './parentItem.vue'


export default defineComponent({
  name: 'CompositionComponent',
  components:{
    ParentItem,
},
  props: {
    aid:{
      type: Number,
      required:true
    }
  },
  setup(props) {
    let items =reactive(Array<parentStruct>());
    const {load,controller}=plane()
    const {getList}=controller()

    const getSnippets = (from: number, size: number) => {
      if (items.length === 0) {
        console.log('There is literally nothieng to load')
        return
      } else {
        console.log(`getsnippets ${from}  ${size}`)
      }

      return items.slice(from, from size)
    }

    onMounted(()=>{
      console.log("parent list on mounted")
      load()
      items = getList(props.aid)??[]
      console.log(items)
    })

    watch(items,()=>{
      console.log('items change in watch')
    },{ deep : true})
        
    return { items,getSnippets};

  },
});
</script>

Child Component:

<template>
  <div>
    <TxtBoxComponent
      :txt="parentItem"
      @updateTxt="
        (text) => {
          modRepl(parentItem, text);
        }
      "
    ></TxtBoxComponent>
    <q-btn @click="addRow">add Props</q-btn>
    <div >localRef:</div>
    <TxtBoxComponent
      :txt="localPropItem"
      @updateTxt="
        (text) => {
          modRepl(localPropItem, text);
        }
      "
    ></TxtBoxComponent>
  </div>
</template>
 <script lang='ts'>
import {
  defineComponent,
  PropType,
  ref,
  Ref,
  onMounted,
  watch,
  reactive,
} from 'vue';
import { plane } from '../controls/control';
import { parentStruct, testStruct } from '../controls/types';
import TxtBoxComponent from './textboxComponent.vue';

export default defineComponent({
  name: 'ParentItem',
  props: {
    parentItem: {
      type: Object as PropType<parentStruct>,
      required: true,
    },
  },
  components: {
    TxtBoxComponent,
  },
  setup(props) {
    let localPropItem = reactive(props.parentItem);
    let aid: Ref<number> = ref(0);
    const { load, controller } = plane();
    const { add, modD, modReplace, del } = controller();
    const addRow = () => {
      const e: testStruct = {
        tid: 0,
        b: "test",
      };
      const p: parentStruct = {
        id: props.parentItem.id   1,
        d: "test",
        e: e,
        aid: aid.value,
      };
      add(p);
    };
    const modDelete = (parent: parentStruct) => {
      modD(parent);
    };
    const modRepl = (parent: parentStruct, txt: string) => {
      console.log(`modRepl event return: ${txt}`);
      modReplace(parent, txt);
      console.log(`modRepl props item : ${props.parentItem.d}`);
    };
    onMounted(() => {
      console.log(`ParentItem mounted ${props.parentItem.d}`);
      load();
    });
    watch(
      props.parentItem,
      () => {
        console.log(`props.parentItems change in watch ${props.parentItem.d}`);
      },
      { deep: true }
    );

    return {
      addRow,
      modDelete,
      modRepl,
      del,
      localPropItem,
    };
  },
});
</script>

Controls

import { reactive } from 'vue';
import { store } from './store';
import { parentStruct, testStruct } from './types';

const controller = () => {
  // const {store}=storage()
  const add = (parent: parentStruct) => {
    console.log('control add function');
    const items = store.get(parent.aid.toString());
    
    if (items) {
        items.splice(items.length,0,parent)
      store.set(parent.aid.toString(), items);

      console.log(`controller item length = ${items?.length}`);
    }
  };
  const del = (aid: number, id: number) => {
    const items = store.get(`${aid}`);
    if (items) {
      const idx = items.findIndex((item) => {
        return item.id == id;
      });
      items.splice(idx, 1);
    }
  };
  const modD = (parent: parentStruct) => {
    const items = store.get(parent.aid.toString());
    if (items) {
      const idx = items.findIndex((item) => {
        return item.id == parent.id;
      });
      items[idx].d = parent.d;
    }
  };
  const modReplace = (parent: parentStruct, txt: string) => {
    const items = store.get(parent.aid.toString());

    if (items) {
      const idx = items.findIndex((item) => {
        return item.id == parent.id;
      });
      console.log(`before mod ${items[idx].d}`);
      parent.d = txt;
      items[idx] = parent;
      console.log(`after mod ${items[idx].d}`);
    }
  };
  const getList = (aid: number) => {
    const re = store.get(`${aid}`);
    if (re) return reactive(re);
    else {
      throw new Error('no list');
    }
  };
  return {
    add,
    del,
    modD,
    modReplace,
    getList,
  };
};

export const load = () => {
  // const {store} = storage()
  let arr: parentStruct[];
  for (let i = 0; i < 3; i  ) {
    arr = [];
    for (let x = 0; x < 10; x  ) {
      const test: testStruct = {
        tid: x   i,
        b: `${x}`,
      };
      const newItem: parentStruct = {
        id: x,
        d: `item ${x}`,
        e: test,
        aid: i,
      };
      arr.push(newItem);
    }
    console.log('test');
    // store.set(`${i}`,arr)
    store.set(`${i}`, arr);
  }
  return;
};
const plane = () => {
  return { store, load, controller };
};

export { plane };

import { reactive } from 'vue';

import { parentStruct } from './types'

export const store = reactive(new Map<string,parentStruct[]>())

CodePudding user response:

It's better to define an inner field inside the reactive function :

import { reactive } from 'vue';

import { parentStruct } from './types'

export const store = reactive({ state : new Map<string,parentStruct[]>() })

then replace any store.get or store.set by store.state.get or store.state.set

CodePudding user response:

In the end i changed list component script to this :

    setup(props) {
    const { load, controller } = plane();
    const { getList } = controller();

    let items = ref(Array<parentStruct>());
    const getSnippets = (from: number, size: number) => {
      if (items.value.length === 0) {
        console.log('There is literally nothieng to load');
        return;
      } else {
        console.log(`getsnippets ${from}  ${size}`);
      }

      return items.value.slice(from, from   size);
    };

    onMounted(() => {
      console.log('parent list on mounted');
      console.log(items);
    });

    watch(
      items,
      () => {
        console.log('items change in watch');
      },
      { deep: true }
    );
    const stop = watchEffect(()=>{
      items.value = getList(props.aid)??[]
    })
    return { getSnippets, items  };
  },
});

Not sure if this is the best way of doing but if anyone has a better answer please let me know thanks.

  • Related