#Unable to use redirect() to redirect to the /login page from firebase's onAuthStateChanged function.

7 messages · Page 1 of 1 (latest)

tired mulch
#

I have a loader function ProfileLoader() in the /profile route. As of my understanding of loaders, when I click on the Profile button on my website, the ProfileLoader() function runs, and after that it redirects to /profilepage. But I am not being redirected to the /login page if I'm not logged in. But the console.log("User is not logged in") is getting printed in the console. The login and logout functionality works well. But the redirect() is not working as expected.

Also why do I need to return <Outlet />; in ProfileLoader.jsx at the bottom. Removing that shows the <NotFound404 /> element. As far as I know, <Outlet /> is used to tell the parent route where to render the children route. But I am not able to understand why return <Outlet />; is used in ProfileLoader.jsx.

rare sandal
#

Do you happen to have this code either on Scrimba or on GitHub? I’d be interested to play around with it to see what the problem is.

tired mulch
#

Just add firebase config object in the src/firebaseConfig.js file

edgy acorn
#

To my understanding of loaders, they are vanilla js functions. You shouldn't really be returning any jsx from them at all. The information from those loaders get passed to hooks that you can use to grab that information in your page component. The return value of profileLoader should be the user's profile (based on the name). And that information can be grabbed from the useLoaderData hook inside the Profile component.

Another thing would be is that OnAuthStateChanged is an observable. The value inside the callback is what's getting returned but no value is actually being returned from the loader except an Outlet. You could try throwing the redirect and see if that works. But I do believe that, given the current code, Outlet will always be returned first. This might cause some sync issues. Hard to say for sure just looking at the code.

one, more simple, solution would be to use auth.currentUser inside the profileLoader function.

const profileLoader = () => {
  const auth = getAuth()
  const user = auth.currentUser
  if(user) {
    return user // or the profile information or UID
  } else {
    return redirect('/login') // or throw it
  }
  // no need to return any jsx return the user or the redirect
}

Since getAuth might be in an intermediate state, and you may want the actual value, you need to use onAuthStateChanged another, not so elegant, solution would be to do something like this:

const profileLoader = async () => {
  const auth = getAuth()
  return await new Promise((resolve, reject) => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if(user) {
        unsubscribe() //unsubscribe from the observer
        resolve(user) //or profile or the UID
      } else {
        reject(redirect('/login')) //reject (throw) with the redirect
      }
    })
  })
}

Then in the Profile component:

const Profile = () => {
  const profile = useLoaderData() //user or profile or UID
  /* rest of code */
}
edgy acorn
#

There may be other things to take into consideration, this is just what I see so far. Hopefully that helps get you going.

tired mulch
#

Both the snippet you have provided, works. Thanks! However I have one more question, how is the code from second snippet working, like I am unable to understand the flow of the code. Mostly the unsubscribe() function. Why are we calling it inside if(user) block?