Vue3 + typescript + vuex4 [Help]
Tags: vue
Published: 2023-06-22 19:57:43

I'm trying to work with vuex4 and vue3 composition api (SFC)  with typescript. I'm not seeing the reactivity and I think i'm not understanding the docs correctly. My issue is the data I'm trying to load from a .json file doesn't initially load (onMounted) when the component is created, and thus I don't have access to any of the data. But on a hot-reload (vite) the data is accessible. Assuming because it was loaded in the state in the previous mounting of the component. Here is my code, Ill try to explain it in depth.

store/index.ts

```
import { Athlete } from './../Athlete';
import { type InjectionKey } from 'vue'
import { createStore, Store, type ActionContext, useStore as baseUseStore } from 'vuex'
import { api } from '../api';

export interface State {
    athletes: Athlete[]
}

export const key: InjectionKey<Store<State>> = Symbol();

const Mutations = {
    SetAthletes: 'setAthletes'
}

export const Actions = {
    GetAthletes: 'getAthletes'
}

export const Getters = {
    GetAthlete: 'getAthlete'
}

export const athleteStore = createStore({
    state: {
        athletes: [],
    },
    getters: {
        [Getters.GetAthlete]: (state: State): Athlete => state.athletes[0]
    },
    mutations: {
        [Mutations.SetAthletes]: (state: State, athlete: Athlete) => {
            state.athletes.push(athlete);
            state.athletes = [...state.athletes];
        }
    },
    actions: {
        [Actions.GetAthletes]: async (context: ActionContext<State, State>) => {
            const athlete = await api.getAthletes();
            context.commit(Mutations.SetAthletes, athlete);
        }
    }
});
export function useStore () {
    return baseUseStore(key)
}
```

api.ts

```
import AthleteData from '@/assets/data.json';

interface IApi {
    getAthletes: () => Promise<Athlete>;
}

const getAthletes = async (): Promise<Athlete> => {
    const jsonObj = AthleteData.data[0];
    return messageToAthlete(jsonObj);
}

export const api: IApi = {
    getAthletes,
}

export default api;
```

main.ts

```
import { athleteStore, key } from './modules/Athlete/store'

const app = createApp(App)
  .use(router)
  .use(vuetify);

app.use(athleteStore, key);

app.mount('#app');
```
and finally my component

```
<script setup lang="ts">
import { Athlete } from '@/modules/Athlete/Athlete';
import { Getters, useStore } from './store';
import ReportTableVue from '../../components/ReportTable.vue';
import { ref, onMounted, computed } from 'vue';

const store = useStore();
store.dispatch('getAthletes');

// onMounted(() => {
//   store.dispatch('getAthletes');
// })

// const athlete: Athlete = ref(store.getters[Getters.GetAthlete]).value
//const athlete: Athlete = computed(() => store.state.athletes[0]).value

//console.log("athlete: ", athlete);

</script>
```
You can see I tried a few things in the component but nothing worked as expected. In the api layer there is a conversion to cast it to the type `Athlete()` I just didn't include it because it's a bit of code. When I hard refresh the browser I keep getting `undefined`. Checking the dev tools I can see all the data is there in the state, just not accessible. Here are the docs I referred to and tried before posting this:

https://vuex.vuejs.org/guide/typescript-support.html
https://stackoverflow.com/questions/64010072/how-to-use-vuex-mapgetters-with-vue-3-sfc-script-setup-syntax

Any help is appreciated!