How Do I Watch Variable in Framework7 Store

Viewed 257

I started building my app using the new built in store system and Im trying to avoid using vuex. I have a variable that changes frequently. I have used the following code when working with vuex.

store.watch((state) => state.status, (newValue) => { self.status= newValue; });

I am hoping there is a way to do it without vuex. Any help is greatly appreciated.

<template>
  <f7-navbar>
    <f7-nav-left>
      <f7-link icon="icon-bars" href="/leftsidebar/" data-ignore-cache="true">
         <f7-icon ios="f7:menu" md="material:menu" aurora="f7:menu"></f7-icon>
      </f7-link>
    </f7-nav-left>
    <f7-nav-right>
      <f7-link icon="icon-bars" href="/connect/" data-ignore-cache="true">
         <f7-icon ios="f7:globe" md="material:public" aurora="f7:globe"></f7-icon>
      </f7-link>
      <f7-link icon="icon-bars" href="/rightsidebar/" data-ignore-cache="true">
         <f7-icon ios="f7:gear_alt_fill" md="material:settings" aurora="f7:gear_alt_fill"></f7-icon>
      </f7-link>
    </f7-nav-right>
  </f7-navbar>
</template>
<script>
  import store from '../js/store';
  export default {
    name: "pageheader",
    props: {
      f7router: Object,
    },
    data() {
      return {
        offline:true
      };
    },
    mounted(){
      var self = this;
      self.offline = store.state.offline;

      // This is where I am trying to create the watcher
      store.watch((state) => state.offline, (newValue, oldValue) => { 
         self.offline = newValue; });
      }
  };
</script>

Update: I have included an example of a header component where I wish to watch the offline status in my store.

2 Answers

creating a new value and updating it with watcher can be dangerous in some cases, because components can have different sources of data; for fraction of seconds, the component may preserve previous data before the value gets updated, whereas data in store is already updated. data must come from a single source to prevent having different states for each components. this may lead to unexpected bugs.

instead, I've made a framework7 store reactive in Vue by wrapping it with Vue Observer.

// store.js
// create default framework7 store
import { createStore } from "framework7";

const store = createStore({
  state: {
    users: []
  },
  actions: {
    setUsers({ state }, data) {
      state.users = data;
    }
  }
});

export default store;

// -----------------
// vueStore.js
// wrap the framework7 store with Vue's reactivity function

import store from "./store";
import Vue from "vue";

// store.state becomes reactive
Object.defineProperty(store, "state", Vue.observable(store.state));

export default store;

// -----------------
// MyComponent.vue
<script>
import store from "./vueStore";

export default {
  name: "App",
  computed: {
    users: {
      // listen to an existing value,
      // instead of creating a new value and attach the watcher
      get() {
        return store.state.users;
      },
    },
  },
  methods: {
    updateUsers() {
      store.dispatch("setUsers", [1, 2, 3, 4]);
    },
  },
};
</script>

in this code, if a user triggers .updateUsers method, the value also gets updated in the component.

here is a working code:

https://codesandbox.io/s/framework7-store-reactive-vue-tded6?file=/src/App.vue:182-457

Presumably, your value store.state is a reactive object created by either Vuex or hand-rolled using Vue.observable(). Beyond that, you'll want to make sure that your watcher gets destroyed when the component is destroyed. This can be achieved if you use Vue's this.$watch() API instead:

<script>
import store from '../js/store';
export default {
  // ...
  mounted(){
    var self = this;

    // Keep `offline` in sync with store
    var off = self.$watch(
      () => store.state.offline,
      (newValue) => (self.offline = newValue),
      { immediate: true }
    );
  }
};
</script>

If you're using Framework7's Store, then you'll need to use their useStore helper to get a reactive reference to your state:

<script>
import { useStore } from "framework7-vue"
import store from "../js/store"

export default {
  setup() {
    const offline = useStore(store, "offline")

    return { offline }
  }
}
</script>

See: Usage with Vue Components

Related