Home > front end >  how to wait for session loading?
how to wait for session loading?

Time:01-04

I am using next-auth for user authentification, when the user signin I store the accessToken in the session

in my page [trackId].js each time the user updates the track the value of refresh (which is a useState hook) changes so useEffect runs and get the new track.

 useEffect(() => {
    async function refreshPage() {
      console.log(session); // <-- output in the image below
      await axiosPrivateWithToken(session.data.accessToken)
        .get(`/track/get/${trackId}`)
        .then((res) => {
          setGetedTrack(res.data);
        })
        .catch((error) => {
          console.log("refreshPage for track has catched an error : ", error);
        });
    }
    refreshPage();
  }, [refresh]);

so far so good all works fine the problem is when the user enters the URL manually, I get this error

TypeError: Cannot read properties of undefined (reading 'accessToken')

and this is because when the window reloads the session is loading and does not have the accessToken yet, data is still undefined

enter image description here

any suggestions ? thank you for your attention

CodePudding user response:

Can't you just add session.data.accessToken to the dependency list, so it refreshes once you have your access token?

useEffect(() => {
  async function refreshPage() {
    if (!session.data || !session.data.accessToken) return;
    console.log(session); // <-- output in the image below
    await axiosPrivateWithToken(session.data.accessToken)
      .get(`/track/get/${trackId}`)
      .then((res) => {
        setGetedTrack(res.data);
      })
      .catch((error) => {
        console.log("refreshPage for track has catched an error : ", error);
      });
  }
  refreshPage();
}, [refresh, (session.data || { accessToken: '' }).accessToken]);

CodePudding user response:

One solution could be to check if the session has been initialized before attempting to access the accessToken property. You could do this by adding an additional condition to your refreshPage function:

if (session && session.data) {
  await axiosPrivateWithToken(session.data.accessToken)
    .get(`/track/get/${trackId}`)
    .then((res) => {
      setGetedTrack(res.data);
    })
    .catch((error) => {
      console.log("refreshPage for track has catched an error : ", error);
    });
}

This will ensure that the refreshPage function will only run if the session has been initialized and has a data property.

Alternatively, you could also consider wrapping the entire useEffect hook with a check for the presence of the session object, like so:

if (session && session.data) {
  useEffect(() => {
    async function refreshPage() {
      console.log(session); // <-- output in the image below
      await axiosPrivateWithToken(session.data.accessToken)
        .get(`/track/get/${trackId}`)
        .then((res) => {
          setGetedTrack(res.data);
        })
        .catch((error) => {
          console.log("refreshPage for track has catched an error : ", error);
        });
    }
    refreshPage();
  }, [refresh]);
}

This will ensure that the useEffect hook doesn't run if the session object is not present.

CodePudding user response:

Instead of checking if session is defined each time you need it, a good pattern is this one, you declare an Auth component :

function Auth({ children }: { children: JSX.Element }) {
  // if `{ required: true }` is supplied, `status` can only be "loading" or "authenticated"
  const router = useRouter();
  const { status } = useSession({ required: true, onUnauthenticated() {
    router.push('/login');
  }, })

  if (status === "loading") {
    return <div>Loading...</div>
  }

  return children
}

And in your _app.tsx, you add it like this so session will always be defined:

  <Layout>
      {Component.auth ? (
        <Auth>
          <Component {...pageProps} />
        </Auth>
      ) : (
        <Component {...pageProps} />
      )}
  </Layout>

So if you need a Page where session has always to be defined, you juste have to add an Auth property to your page, for exmaple if you have a page named 'account' :

Account.auth = {
    
}

And then, session will always be defined in your page or you'll be redirect to /login

  • Related