Friday, 6 October 2023

What causes the failure to protect a route in this React.js app?

I am making a chat app with React 18 and Firebase 9.

The chat route - which is the root app - is supposed to be accessible only after authentication.

In App.js I have:

import { useContext } from 'react';
import {
  createBrowserRouter,
  createRoutesFromElements,
  Route,
  RouterProvider,
  Navigate
} from 'react-router-dom';
import RootLayout from './layouts/RootLayout';
import AuthLayout from './layouts/AuthLayout';
import Chat from './pages/Chat';
import Register from './pages/Register';
import Login from './pages/Login';
import { AuthContext } from './contexts/AuthContext';

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<RootLayout />}>
      <Route index
        element={
          <ProtectedRoute>
            <Chat />
          </ProtectedRoute>
        } />

      <Route path="auth" element={<AuthLayout />}>
        <Route path="register" element={<Register />} />
        <Route path="login" element={<Login />} />
      </Route>
    </Route>
  )
);

function App() {
  const { currentUser } = useContext(AuthContext);

  const ProtectedRoute = ({ children }) => {
    if (!currentUser) {
      return <Navigate to="/auth/login" />;
    }
    return children
  };

  return (
    <RouterProvider router={ router } ProtectedRoute={ ProtectedRoute } />
  );
}

export default App;

In src\contexts\AuthContext.js I have:

import { createContext, useEffect, useState } from "react";
import { auth } from "../firebaseConfig";
import { onAuthStateChanged } from "firebase/auth";

export const AuthContext = createContext();
export const AuthContextProvider = ({ children }) => {
  const [currentUser, setCurrentUser] = useState({});

  useEffect(() => {
    const unSubscribe = onAuthStateChanged(auth, (user) => {
      setCurrentUser(user);
      console.log(user);
    });

    return () => {
      unSubscribe();
    };
  }, []);

  return (
    <AuthContext.Provider value=>
      {children}
    </AuthContext.Provider>
  );
};

I use the AuthContextProvider in index.js:

import { AuthContextProvider } from './contexts/AuthContext';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <AuthContextProvider>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </AuthContextProvider>
);
reportWebVitals();

The Chrome console throws this error from App.js:

Uncaught ReferenceError: ProtectedRoute is not defined

What am I doing wrong?

UPDATE

This version of App.js throws a React Hook "useContext" cannot be called at the top level error:

const { currentUser } = useContext(AuthContext);

const ProtectedRoute = ({ children, currentUser }) => {
  if (!currentUser) {
    return <Navigate to="/auth/login" />;
  }
  return children
};

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<RootLayout />}>
      <Route index
        element={
          <ProtectedRoute currentUser={ currentUser }>
            <Chat />
          </ProtectedRoute>
        } />

      <Route path="auth" element={<AuthLayout />}>
        <Route path="register" element={<Register />} />
        <Route path="login" element={<Login />} />
      </Route>
    </Route>
  )
);

export default function App() {
  return (
    <RouterProvider router={router} />
  );
}


from What causes the failure to protect a route in this React.js app?

No comments:

Post a Comment