Home > Enterprise >  React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for c
React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for c

Time:12-07

I have built a private route using the auth API from Firebase v9 and React-router-dom v6 to access admin part, when I log in it redirect me to the admin page but the page is blank and the console log this "React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined." And ask me to "Check your code at PrivateRoute.jsx:7.". Thank you for your help =).

PrivateRoute.jsx

import React from 'react'
import {Navigate} from 'react-router-dom'
import { auth } from '../../Firebase'

function PrivateRoute({component: Component}) {
    const user = auth.currentUser
    return user ? <Component /> : <Navigate to='/login'/> 
    }
export default PrivateRoute

App.jsx (where the private route is used)

import {BrowserRouter, Route, Routes } from 'react-router-dom';
import Admin from './Components/Admin/Admin'

function App() {
  return (
  <BrowserRouter>
      <div className="App">
        <Routes>
          <Route 
            path="/admin" 
            element={
              <PrivateRoute>
                <Admin />
              </PrivateRoute> 
            } 
          />
        </Routes>
      </div>
  </BrowserRouter> 
  );
}

export default App;

I let you the Firebase file and the AuthContext to figure out

Firebase.js

import {initializeApp} from 'firebase/app'
import {serverTimestamp, getFirestore} from 'firebase/firestore'
import {getStorage} from 'firebase/storage'
import {getAuth} from'firebase/auth'

const firebaseConfig = { config }
const app = initializeApp(firebaseConfig)
export const timestamp = serverTimestamp()
export const projectFirestore= getFirestore(app)
export const projectStorage= getStorage(app)
export const auth = getAuth(app)

export default app

AuthContext.jsx

import {useContext, useState, useEffect, createContext} from 'react'
import { auth } from '../../Firebase'
import {  createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, onAuthStateChanged} from "firebase/auth";

const AuthContext = createContext()

export function useAuth() {
     return useContext(AuthContext)
}

export function AuthProvider({children}) {
    const [currentUser, setCurrentUser] = useState()
    const [loading, setLoading] = useState(true)
    
    function register(email, password){
        return createUserWithEmailAndPassword(auth, email, password)
    }
    
    function login(email, password){
        return signInWithEmailAndPassword(auth, email, password)
    }

    function logout() {
        signOut(auth)
    }

    useEffect(() =>{
      const unsubscribe = onAuthStateChanged(auth ,(user) => {
        setCurrentUser(user)
        setLoading(false)
        })
        return unsubscribe
    }, [])

    const value = {
        currentUser,
        login,
        register,
        logout
    }

    return (
        <AuthContext.Provider value={value}>
            {!loading && children}
        </AuthContext.Provider>
    )
}

CodePudding user response:

The way authentication in RRDv6 changed significantly from v5. Gone are custom route components, replaced by wrapper components.

Given:

<BrowserRouter>
  <div className="App">
    <Routes>
      <Route
        path="/admin"
        element={(
          <PrivateRoute>
            <Admin />
          </PrivateRoute>
        )}
      />
    </Routes>
  </div>
</BrowserRouter>

The PrivateRoute wrapper just needs to render its children prop instead of a component prop.

function PrivateRoute({ children }) {
  const user = auth.currentUser;
  return user ? children : <Navigate to='/login' replace />;
}

A common pattern however is to render in Outlet component instead, and wrap nested protected routes.

Example:

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

const PrivateWrapper = () {
  const user = auth.currentUser;
  return user ? <Outlet /> : <Navigate to='/login' replace />;
}

...

<BrowserRouter>
  <div className="App">
    <Routes>
      <Route path="/admin" element={<PrivateWrapper />} >
        <Route path="/admin" element={<Admin />} />
        ... other nested protected routes ...
      </Route>
    </Routes>
  </div>
</BrowserRouter>
  • Related