vue.jsvuejs3vue-reactivity

How to separate user changes to objects from changes to objects by my code?


What are the best practices for sending user changes to the server of an object received from the server? Now I don't understand how to separate the change when receiving data from the server and the user change.

I have this code. The problem is that the function saver() is called when receiving data from the server.

import { defineStore } from 'pinia';
import { api, getError } from 'boot/axios';
import { ref, watch, WatchStopHandle } from 'vue';

interface Data {
  A: string;
  B: Data[];
}

export const useDataStore = defineStore('data', () => {
  const data = ref<Data[]>([]);
  const loading = ref(false);

  let stopSaver: WatchStopHandle | undefined;
  async function saver() {
    api.post('/save-data', data);
  }

  async function load(id: number): Promise<void> {
    try {
      stopSaver && stopSaver();
      stopSaver = undefined;

      loading.value = true;

      const res = await api.post('/get-data', id);
      data.value = res.data;

      loading.value = false;

      stopSaver = watch(data, saver, { deep: true });
    } catch (error) {
      loading.value = false;
      throw error;
    }
  }

  return { data, loading, load };
});

Solution

  • code that works as it should play.vuejs.org

    <script setup>
    import { ref, watch } from 'vue'
    
    const data = ref('')
    let stopWatch = watch(data, Saver);
    
    async function AsyncLoader() {
      setTimeout(() => {
        stopWatch();
        data.value="data from server";
        stopWatch = watch(data, Saver);
      })
    }
    async function Saver() {
      if (data.value==="data from server") 
        alert("I'm only waiting for user edited data, not server data")
      else
        alert("good change")
    }
    </script>
    
    <template>
      <button @click="AsyncLoader">Load data from server</button>
      <input  v-model=data>
    </template>