Composition API State Management is not reactive

I’m using composition api for state management but it’s not reactive.

This is my store file :

import { readonly, reactive } from "@vue/reactivity";
const state = reactive({
    lang: "en",
    page: 1,
    words: [
        {
            word: "Hello",
            repeat: 92,
            sentences: [],
        },
        { word: "Love", repeat: 128 },
        { word: "Good", repeat: 50 },
        { word: "New", repeat: 12 },
        { word: "Hello", repeat: 12 },
        { word: "Love", repeat: 12 },
        { word: "Good", repeat: 12 },
        { word: "New", repeat: 12 },
        { word: "Hello", repeat: 12 },
        { word: "Love", repeat: 12 },
        { word: "Good", repeat: 12 },
        { word: "New", repeat: 12 },
        { word: "Hello", repeat: 12 },
        { word: "Love", repeat: 12 },
        { word: "Good", repeat: 12 },
        { word: "New", repeat: 12 },
    ],
});

const methods = {
    changePage(i: number): void {
        state.page = i;
    },
    emptyTheList() {
        state.words = [];
    },
};

export default { state, methods };

And this is a component that is using the injected store :

<template>
    <div class="btn-group bg-gray-50 mt-6 pt-6 pb-6 flex justify-center">
        <button class="btn" :id="wordsInfo.state.page">&#60;&#60;</button>
        <button
            class="btn"
            v-for="i in numberOfPages"
            v-bind:key="i"
            :class="page === i && 'btn-active'"
            @click="changePage(i)"
        >
            {{ i }}
        </button>
        <button class="btn">&#62;&#62;</button>
    </div>
</template>
<script>
import { ref, computed, inject } from "vue";

export default {
    name: "WordCardsPagination",
    props: {
        func: Function,
    },
    setup(props, context) {
        console.log(props.func);
        const wordsInfo = inject("wordsInfo");
        const numberOfPages = computed(() => {
            return Math.ceil(wordsInfo.state.words.length / 12);
        });
        const page = ref(wordsInfo.state.page);

        const changePage = (i) => {
            wordsInfo.methods.changePage(i);
            page.value = wordsInfo.state.page;
        };
        return {
            numberOfPages,
            wordsInfo,
            page,
            changePage,
        };
    },
};
</script>

the code above runs with no problem but if instead of page, wordsInfo.state.page is used page ref is removed :

<button
            class="btn"
            v-for="i in numberOfPages"
            v-bind:key="i"
            :class="wordsInfo.state.page === i && 'btn-active'"
            @click="wordsInfo.methods.changePage(i)"
        >
            {{ i }}
        </button>

the component is not reactive anymore, even though console.log shows that the value has changed

Answer

Well I’m not 100% sure this should be an answer but maybe it will help some people in the future…

In this case problem was in the import used in the “store” file – import { readonly, reactive } from "@vue/reactivity" while the rest of the app was using import { ... } from 'vue'

So as a result the “store” was using different Vue module (reactivity code) than the rest of the app. It is hard to say exactly why without knowing much more about the OP setup but as a rule of thumb try to stick with import { xx } from "vue" and do not mix it up!