简体   繁体   中英

Vue3/Vuex Object from reactive() looses reactivity once passed as payload in mutation to vuex

I know, or maybe I don't, but some might be scratching their heads like 'Why do you want a reactive object that you can use with Provide/Inject into your Vuex Store?' ... Well because I can and I gotta'...

Okay, DAD jokes aside I have this plugin that implements authentication and once inistalled into the app I do a "caveman style" vuex plugin function to register it into the namespaced User module of my vuex store, by calling a mutation and passing the reactive const object User , that is wrapped in the reactive function of Vue 3, as the payload. Now the funny thing is it loses its reactivity once registered into the store while the Provide/Inject still work totally fine :)

Here's some spaghetti:

AuthLink.vue

...

export default defineComponent({
    setup() {
        const auth = inject("Auth") as IAuthPluginProperties;

        async function logInFromLink(
            withPopUp = false,
            options?: {
                redirectLoginOptions?: RedirectLoginOptions;
                popupConfigOptions?: PopupConfigOptions;
                analytics: undefined;
            }
        ): Promise<void> {
            if (withPopUp) return auth.loginWithPopup();

            //* Potentially add analytics for how many people logged in with the link, from which page etc.

            return await auth.loginWithRedirect(options?.redirectLoginOptions);
        }

        function logout(logoutOptions?: LogoutOptions): void {
            auth.logout(logoutOptions);
        }

        return {
            auth,
            logInFromLink,
            logout
        };
    }
});
</script>

Plugin - index.ts

...
export default {
    install: async (app: App, options: pluginInstallOptions): Promise<void> => {
        app.config.globalProperties.$auth = Plugin.AuthPluginProperties;
        app.provide("Auth", Plugin.AuthPluginProperties);

        /*
         * Could Handle defaulting to.env vars
         *    & then -> if !env vars throw err
         */

        

        if (options.useStore) {
            if (!store.hasModule("User")) {
                throw new Error(
                    "🙈🙉🙊 Something evil is lurking in the shadows...`User` vuex store module has not been registered."
                ).stack;
            }

            await vuexPlugin(store, Vue3AuthPlugin.AuthPluginProperties);
       
...

Plugin - main.ts

...

const state = reactive({
    isLoading: false,
    isAuthenticated: false,
    user: undefined,
    popupOpen: false,
    error: null
}) as IAuthStateProp;

export const AuthPluginProperties = reactive({
    isAuthenticated: computed(() => state.isAuthenticated),
    isLoading: computed(() => state.isLoading),
    user: computed(() => state.user),
    ...some more functions passed here
}) as IAuthPluginProperties;

...

store/modules/User/Mutations.ts

import { MutationTree } from "vuex";
import { UserMutations, UserMutationTypes, UserState } from "@/store/types";
import IAuthPluginProperties from "~interfaces/Auth/IAuthPluginProperties";

const mutations: MutationTree<UserState> & UserMutations = {
    [UserMutationTypes.INITIALIZE_PLUGIN](state: UserState, payload: IAuthPluginProperties) {
        state.User = payload;
    }
};

export default mutations;

[EDIT 1]

Forgot to add the code for the "caveman style" vuex plugin function

auth-vuex-plugin.ts

import { AuthVuexPlugin } from "../types";

const plugin: AuthVuexPlugin<Record<string, unknown>> = async (store, payload) => {
    try {
        await store.dispatch("User/INITIALIZE_PLUGIN", payload);
    } catch (err) {
        throw new Error(`🙈🙉🙊 Something evil happened... Vuex init failed: ${err}`);
    }
};

export default plugin;

Actually achieved what I was after by passing the payload as ToRefs(payload) as well as typed it with the generic ToRefs provided by Vue like ToRefs<IAuthState> .

I'm unsure if this is the best way of going about it, but will leave room for anyone to tag along or if I manage to find something better :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM