Home > Enterprise >  React-Firebase routing and authentication approach
React-Firebase routing and authentication approach

Time:01-05

I want to learn the correct approach for firebase routing authetication,what I mean is:

function App() {
  const auth = getAuth();

  if (!auth) {
    <Spinner />;
  }

  return (
    <>
      {auth && (
        <Router>
          <Routes>
            <Route path='/' element={<PrivateRoute />}>
              <Route index element={<Explore />} />
              <Route path='/offer' element={<Offers />} />
              <Route path='/profile' element={<Profile />} />
            </Route>
            <Route path='/sign-in' element={<SignIn />} />
            <Route path='/sign-up' element={<SignUp />} />
            <Route path='/forgot-password' element={<ForgotPassword />} />
          </Routes>
          <Navbar />
        </Router>
      )}

I have this code-block, at first I thought I should've gotten a useAuth hook which use onAuthStateChanged, but I realize that this auth variable from getAuth is kinda work the same way so why not use it instead of a hook?

and my PrivateRoute looks like this:

function PrivateRoute() {
  const currentUser = getAuth().currentUser;

  return currentUser ? <Outlet /> : <Navigate to='/sign-in' />;
}

the problem is once app mounts, because of there is no app-level state, it stays the same.

Then if I try to log off and put some logic into routing like if user exists, dont' allow routing to signup or signin, it doesn't work.

If I use redux or context API, I would dispatch whenever I login, logout, signup but without them what is the correct set-up for handling this kind of routing?

CodePudding user response:

after some time, i just figured out how to do what I needed to do, so I post it here just in case someone also encounters this problem and seeks help.

If you don't use redux or context api and still want to implement this kind of feature, here's how I do:

So what I needed to do? I want authenticate through firebase, what you need to do -at least what I found- implement a APP/LEVEL/STATE in order to check if user logged in or not and update the app level rendering, that renders the whole app and enforces behaviour accordingly.

So:

function App() {
  const [user, setUser] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setIsLoading(true);

      if (user) {
        setUser(user);
      } else {
        setUser(null);
      }

      setIsLoading(false);
    });

    return unsubscribe;
  }, []);

  if (isLoading) return <Spinner />;

  return (
    <>
      <Router>
        <Routes>
          <Route path='/' element={<PrivateRoute user={user} />}>
            <Route index element={<Explore />} />
            <Route path='/offers' element={<Offers />} />
            <Route path='/profile' element={<Profile />} />
            <Route path='/create-listing' element={<CreateListing />} />
            <Route path='/category/:categoryName' element={<Category />} />
          </Route>
          <Route
            path='/sign-in'
            element={!user ? <SignIn /> : <Navigate to='/' />}
          />
          <Route
            path='/sign-up'
            element={!user ? <SignUp /> : <Navigate to='/' />}
          />
          <Route
            path='/forgot-password'
            element={!user ? <ForgotPassword /> : <Navigate to='/' />}
          />
        </Routes>
        <Navbar />
      </Router>

      <ToastContainer autoClose={1000} />
    </>
  );
}

export default App;

Here, basically after component mounts, we want useEffect to only execute once and set up listener for auth state changing, whenever auth state changes like sign-in or log-out, the code block of onAuthStateChanged runs and when it runs, every time it sets the user if there's one or not, therefore re-renders the component which is App itself, and below the routing works accordingly. If you have a private route as I do, you can just pass the user as a prop, then:

import { Navigate, Outlet } from 'react-router-dom';

function PrivateRoute({ user }) {
  return user ? <Outlet /> : <Navigate to='/sign-in' />;
}

export default PrivateRoute;
  •  Tags:  
  • Related