DEV Community

Thomas Fitzgerald
Thomas Fitzgerald

Posted on

Vue3 + typescript + vuex4 [Help]

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)
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

main.ts

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

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

app.use(athleteStore, key);

app.mount('#app');
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (1)

Collapse
 
lucasvsouza28 profile image
Lucas Souza

I've made an example with pokemons. However, i do think it works with athletes.
codesandbox.io/s/sleepy-lichterman...