Tallboy
Tallboy

Reputation: 13467

Vue 3: Why is my composable not reactive?

I want to use 1 composable from within another. My first composable is basically a super lightweight version of Vuex:

import {
  reactive,
  readonly,
} from 'vue';

const state = reactive({
  settings: {
    loading: true,
  },
  cart: {
    loading: true,
    items: [],
  },
});

export default {
  state: readonly(state),
};

When I try to use this in another composable, the cart is not being reactive.

In my other composable I have:

import store from '@/store';
watch(store.state.cart, () => {
  console.log('test');
});

And it doesn't seem to react to anything. When I try calling .value on it, its undefined, as if it's not a proxy.

I also tried using inject('store') and that seems to do the same thing.

I want to watch when any part of the cart changes.

Upvotes: 3

Views: 2696

Answers (1)

Tallboy
Tallboy

Reputation: 13467

The answer is long and involved, but it basically boils down to:

  1. Part of it is a javascript problem, in that the way I was updating cart was by replacing the entire key of the object with an API call, so the inner cart key was getting updated with a different reference. You can visualize the problem here

  2. I had to use toRef which is subtly different from ref, in that it is specifically for extracting reactive keys out of a reactive object. I thought this only applied to destructuring but it also applies to simply saying const cart = store.state.cart, as when I updated the cart this cart variable would point to the old reference. toRef solves this by writing: const cart = toRef(store.state, 'cart')

Upvotes: 3

Related Questions