0

I'm new to Nuxt 3 (and Vue) and running into a issue with component reuse/caching in development mode. This problem never occurs when I build and preview the application.

The Problem

I'm using a dynamic route with a query parameter for a "magic login" process:

  1. I access the page with the first token: /magic-login?token=token-A

  2. The validation logic runs correctly.

  3. I access the page a second time with a different token: /magic-login?token=token-B

  4. The page loads, but the validation logic is weird. It's like not run at all. It just navigate to /select-role like first logic. and I also see there nothing happend in network tab. So I assume it like cache entire state or something ( or just see that it same route. just navigate to /select-role) I also see there nothing happend in network tab. So I assume it like cache entire state or something ( or just see that it same route. just navigate to /select-role

This is my setup

I have a simple page component that loads a main component.

pages/magic-login.vue (Note: I've tried to force a new component key, but it didn't solve the issue.)

<template>
  <LoginCallbackPage />
</template>

<script setup>
import LoginCallbackPage from '~/context/component/Login/LoginCallback.vue';

definePageMeta({
  layout: false,
  key: (route) => {
    return route.fullPath;
  },
  keepalive: false,
});
</script>

LoginCallbackPage (The component containing the validation logic.)

<template>
  <div>Validating...</div>
</template>

<script setup lang="ts">
import API from '~/context/global/api/api-client'; 
import { useAuthStore } from '~/context/global/store/auth-store'; 
import getApiError from '~/context/global/utils/api/get-error'; 

const route = useRoute();
const toast = useToast();
const config = useRuntimeConfig();
const authStore = useAuthStore();

const redirectToLogin = () => {
  toast.add({
    title: 'Failed to login', 
    color: 'error',
  });
  navigateTo({
    path: '/login',
    query: {
      FAILED_TO_LOGIN: 'true',
    },
  });
};

const handleValidateToken = async (token: string) => {
  try {
    const res = await API.User.ValidateTokenAndGetInfo(token); 

    if (res.status_code === 200) {
      const { token: receivedToken, ...userDataWithoutToken } = res.data;
      if (receivedToken && userDataWithoutToken) {
        authStore.setAuth(receivedToken, userDataWithoutToken);
        return navigateTo('/select-role'); 
      }
    }
    redirectToLogin();
  } catch (error) {
    const err = getApiError(error);

    redirectToLogin();

    throw error;
  }
};

onMounted(() => {
  const token = String(route.query.token);

  handleValidateToken(token);
});
</script>

I also try watch like this but seem not working

watch(
  () => route.query.token, 
  () => {
  const token = String(route.query.token);
  handleValidateToken(token);
  },
  { immediate: true },
);

I use nuxt 3.19.3 and called the API with ofetch

1
  • how does query.token change exactly? Commented Oct 23 at 18:13

2 Answers 2

2
  1. If there is an error occurring, it might be trying to "redirect to login" but the throw error that follows immediately after maybe cancelling something out in the logic flow and obfuscating what is going on.

    You are either redirecting on error or showing an error, I don't think you can do both as a throw tends to cancel operations.

  2. There could be a race condition causing logic to be skipped because there are 2 navigations happing very fast (a "flicker" it is what they refer to it as in the docs).

    This logic I think is best placed in a middleware and work more reliably there, either as a global and triggered when a token is seen or the middleware is assigned to only run on on your LoginCallbackPage.

    A middleware is a much better place to intercept navigation, you can abort a navigation or redirect before the original navigation is fully resolved and prevent the "flicker" and put you in a better stance to mitigate a possible race condition.

Sign up to request clarification or add additional context in comments.

Comments

2

You are running the validation function inside the onMounted hook. this hook just called when the component (page) loads. when your chaning the query in url (in this example token), the page is not changing, and onMounted hook is not calling anymore.

so you need to listen for query token change by your self. In this example using watch is nice. I think using watch in this way is going to work:

watch(  
    () => route.query.token,   
    (newVal) => {    
        console.log('hello, the new value of token is: ', newVal);
        handleValidateToken(newVal);  
    }
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.