2

I am using Next.js and Firebase.

I want to allow users to sign up with Google, but I need to check at the app level whether the users status is "incomplete" or "active".

Here is my useEffect. I listen to userData here and if the status is "incomplete", I redirect the user to the place where I can finish their sign up process (e.g. ask for username).

useEffect(() => {
    if (currentUser && currentUser !== "unauthenticated") {
      const docRef = doc(db, "users", currentUser.uid);
      return onSnapshot(docRef, async (doc) => {
        let data = doc.data() as UserData;
        if (!data) {
          return;
        }
        if (data?.status === "incomplete") {
          router.push("/complete-user-data");
          return;
        }
        setData(doc.data() as UserData);
      });
    }
  }, [currentUser, router, setData]);

This would work however as the useEffect is constantly rerendering due to the router.push("/complete-user-data");, I am in a infinite loop.

Whats the best way of creating a top level listener that will basically block the user based on a certain condition and push them to a certain route?

Is there a way to only push to a route if the user isn't currently on that route (in my case, if they're not on /complete-user-data?)

squish
  • 846
  • 12
  • 24
  • the `useEffect` is taking `router` as a dependency while you're changing it inside the effect, which it triggers a loop. did you try to use an empty `useEffect` dependencies array `[]`? – mocherfaoui Mar 29 '22 at 10:51
  • Ah thats a good point, maybe taking that out will fix it. I added router as a dependancy as I get the warning `React Hook useEffect has a missing dependency: 'router'.`, However I may need to ignore the warning – squish Mar 29 '22 at 11:02
  • I will try now and let you know if it works @mocherfaoui – squish Mar 29 '22 at 11:03
  • @mocherfaoui thank you that worked. If you create an answer, ill accept it. Also, if you have any advice for the `React Hook useEffect has a missing dependency: 'router'. Either include it or remove the dependency array.` warning I am getting, please let me know. Thanks! – squish Mar 29 '22 at 11:08
  • The idea is that if you have dependencies outside the useEffect hook, you should provide them in the dependency []. But if certain dependency is used only inside the hook, then try to initialize it inside the hook. "Either include it or remove the dependency array". But you have to be careful when using outside dependencies, because any change to that dependency will trigger the useEffect hook again. import { useRouter } from 'next/router'; useEffect(() => { const router = useRouter(); // do routing }, [dependency array]) – Victor Mar 29 '22 at 11:28
  • Ahh i see, so I should declare the router inside the useEffect? brilliant, will do that now. Thank you @Victor – squish Mar 29 '22 at 11:35
  • @Victor hmm now I get `React Hook "useRouter" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.`, sorry if i have misunderstood! – squish Mar 29 '22 at 11:37
  • Exactly, if you are need multiple router instances, just initialize router instances for each useEffect so that you don't have a dependency on something that could change and trigger the useEffect again. And as a good practice the useEffect dependencies should be included inside the useEffect callback where possible, to avoid unwanted changes. – Victor Mar 29 '22 at 11:40
  • Do you use getServerSideProps or getStaticProps? – Matt Mar 29 '22 at 11:43
  • It seems you cannot call useRouter() inside a useEffect to build a new instance, because hooks should be declared in the same order at the top of the component. That's a bit tricky... – Victor Mar 29 '22 at 11:46
  • Try using `import Router from "next/router"` the global router and `Router.push("/new/url")` inside the useEffect, without having a dependency to useRouter or needing a router instance. If that doesnt work, then you can try window.location.href = "new location" – Victor Mar 29 '22 at 11:53
  • @Victor hi there, using the global router did remove the warning and still works as expected, thank you! I wonder what the difference is between the two?.. – squish Mar 29 '22 at 11:58
  • The difference is that using the Router object is the imperative way of managing routing and the useRouter is a hook provided by the Router object for functional pattern. You can read more about it here: [Git Discussion](https://github.com/vercel/next.js/discussions/18522) – Victor Mar 29 '22 at 12:06

0 Answers0