Home > Back-end >  Passing Reactive State from Vuex to Composable
Passing Reactive State from Vuex to Composable

Time:09-21

I'm working on a composable that's meant to encapsulate some logic with Vue3 and Vuex. The composable is working with a "feed" that is liable to change in the future, and comes from Vuex.

I'd like the composable to return the status of that feed when the feed changes as a computed value.

However, I'm unclear on how to fetch/wrap the value from Vuex so this computed property will change when the value in Vuex changes. For instance, at the top of the composable, I'm passing in the ID of the feed, fetching it from Vuex, and then using it in the composable like this:

const feed = store.getters['feeds/getFeedById'](feedId)

I'm then using the feed in a computed, inside of the composable, like this:

const feedIsReady = computed(() => feed.info.ready ? 'READY' : 'NOT READY')

However, when I change the feed object in Vuex via a mutation elsewhere in the application, the feed inside the composable does not change.

I've tried wrapping the feed in a reactive call and it's individual properties with toRefs but those approaches only provide reactivity within the composable itself, and don't capture changes from Vuex.

How would one wrap the feed from Vuex to provide reactivity? I need the changes in Vuex to propagate to my composable somehow.

CodePudding user response:

Did you try to use vuex getter in your composable with computed property:

const feed = computed(() => store.getters['feeds/getFeedById'](feedId));

CodePudding user response:

I see you are using store.getters['feeds/getFeedById'](feedId), which, AFAICT, means that the getter store.getters['feeds/getFeedById'] returns a function, and that the feedId is a parameter passed to the returned function.

If this is the case, this probably won't work, because that function likely doesn't return a reactive value.

I can't see the vuex code so don't know for sure, but assuming this is the case I would do something like this

const store = Vuex.createStore({
  state() {
    return {
      feeds: {
       1334:{info:{ready:false}},
      }
    }
  },
  getters: {
    feeds(state) {
      return state.feeds
    }
  },
  mutations: {
    change(state) {
      state.feeds[1334].info.ready = !state.feeds[1334].info.ready;
    }
  }
});

function watchFeedState(feedid) {
  const feeds = Vue.computed(() => store.getters.feeds)
  const isReady = (v) => v && v.info && v.info.ready ? 'READY' : 'NOT READY';
  const feedReady = Vue.ref(isReady(feeds[feedid]));
  
  Vue.watch(store.getters.feeds, (v) => {
    feedReady.value = isReady(v[feedid])
  });
  
  return feedReady
}

const app = Vue.createApp({
  setup() {
    const store = Vuex.useStore();
    
    const isReady = watchFeedState(1334); // <= the feed from a higher order function
    
    return {
      isReady,
      change: ()=>{store.commit('change')}
    }
  }
});

app.use(store);

app.mount("#app");
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuex.global.js"></script>

<div id="app">
  <button @click="change">toggle state</button>
  {{ isReady }}
</div>

This creates a higher order function to watch a specific feed id. This will watch the feeds getter for every change, but only update for a provided feedid.

  • Related