I am learning connecting MongoDB Realm to react by following this article. The problem with this article is that it is outdated, and the newer version of react doesn't support component = {Home} in react-router and perhaps not the render = {()={}} also.
When I shamelessly copy-pasted all code and then ran it I got this warning
index.js:21 Matched leaf route at location "/" does not have an element. This means it will render an with a null value by default resulting in an "empty" page.
then I changed the code(a line) for the Home page just for testing to this
<Route path="/" element={()=><MongoContext.Consumer>{(mongoContext) => <Home mongoContext={mongoContext}/>}</MongoContext.Consumer>} />
Then I got a new warning, LOL!
Warning
Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
I have no what to do now. So, if anyone knows how to solve this, then it will be helpful for me.
App.js
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from "./pages/Home"
import * as Realm from 'realm-web'
import Authentication from './pages/Authentication';
import LogOut from './pages/Logout';
import Navigation from './components/Navigation';
import MongoContext from './MongoContext';
import 'bootstrap/dist/css/bootstrap.min.css'
import { Container } from "react-bootstrap"
import { useEffect, useState } from 'react';
function renderComponent (Component, additionalProps = {}) {
return <MongoContext.Consumer>{(mongoContext) => <Component mongoContext={mongoContext} {...additionalProps} />}</MongoContext.Consumer>
}
function App() {
const [client, setClient] = useState(null)
const [user, setUser] = useState(null)
const [app, setApp] = useState(new Realm.App({ id: "restaurant_app-qbafd" }))
useEffect(() => {
async function init() {
if (!user) {
setUser(app.currentUser ? app.currentUser : await app.logIn(Realm.Credentials.anonymous()))
}
if (!client) {
setClient(app.currentUser.mongoClient('mongodb-atlas'))
}
}
init();
}, [app, client, user])
return (
<BrowserRouter>
<Navigation user={user} />
<MongoContext.Provider value={{ app, client, user, setClient, setUser, setApp }}>
<div className="App">
<header className="App-header">
<Routes>
<Route path="/signup" render={() => renderComponent(Authentication, {type: 'create'})} />
<Route path="/signin" render={() => renderComponent(Authentication)} />
<Route path="/logout" render={() => renderComponent(LogOut)} />
<Route path="/" element={()=><MongoContext.Consumer>{(mongoContext) => <Home mongoContext={mongoContext}/>}</MongoContext.Consumer>} />
</Routes>
</header>
</div>
</MongoContext.Provider>
</BrowserRouter>
);
}
export default App;
Try to wrap all your routes in the MongoContext.Consumer:
<BrowserRouter>
<Navigation user={user} />
<MongoContext.Provider
value={{ app, client, user, setClient, setUser, setApp }}
>
<MongoContext.Consumer>
{(mongoContext) => (
<div className='App'>
<header className='App-header'>
<Routes>
<Route
path='/signup'
element={
<Authentication mongoContext={mongoContext} type='create' />
}
/>
<Route
path='/signin'
element={<Authentication mongoContext={mongoContext} />}
/>
<Route
path='/logout'
element={<LogOut mongoContext={mongoContext} />}
/>
<Route path='/' element={<Home mongoContext={mongoContext} />} />
</Routes>
</header>
</div>
)}
</MongoContext.Consumer>
</MongoContext.Provider>
</BrowserRouter>;
Related
This question already has answers here:
How to create a protected route with react-router-dom?
(5 answers)
Closed 4 months ago.
Help
I'm using a protected route in my React app. But it is not working. All the other Elements are working but when I got to "/account" the whole screen is white. This is my code. It will be really helpful for me if you give that answer. Thank You :)
Protected Route code:
import React, { Fragment } from 'react';
import { useSelector } from 'react-redux';
import { Route, Routes, redirect } from 'react-router-dom';
const ProtectedRoute = ({ element: Element, ...rest }) => {
const { loading, isAuthenticated, user } = useSelector(state => state.user);
return (
<Fragment>
{!loading &&
(<Routes>
<Route
{...rest}
render={(props) => {
if(!isAuthenticated) {
return redirect("/login")
}
return <Element {...props} />
}}
/>
</Routes>
)}
</Fragment>
)
}
export default ProtectedRoute;
I am using ProtectedRoute.js in App.js. Here is the code.
App.js Code:
import React from 'react';
import {BrowserRouter as Router,Route,Routes} from "react-router-dom";
import './App.css';
import Header from "./component/layout/Header/Header.js";
import webFont from "webfontloader";
import Footer from './component/layout/Footer/Footer';
import Home from "./component/Home/Home.js";
import ProductDetails from "./component/Product/ProductDetails.js";
import Products from "./component/Product/Products.js";
import Search from "./component/Product/Search.js";
import LoginSignUp from './component/User/LoginSignUp';
import store from "./store";
import { loadUser } from './action/userAction';
import UserOption from "./component/layout/Header/UserOption.js";
import { useSelector } from 'react-redux';
import Profile from "./component/User/Profile.js"
import ProtectedRoute from './component/Route/ProtectedRoute';
function App() {
const {isAuthenticated, user} = useSelector(state => state.user)
React.useEffect(() => {
webFont.load({
google:{
families:["Roboto","Droid Sans","Chilanka"]
},
});
store.dispatch(loadUser())
}, [])
return (
<Router>
<Header />
{isAuthenticated && <UserOption user={user} />}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/product/:id" element={<ProductDetails />} />
<Route path="/products" element={<Products />} />
<Route path="/products/:keyword" element={<Products />} />
<Route path="/search" element={<Search />} />
<Route path="/account" element={ <ProtectedRoute> <Profile /> </ProtectedRoute> } />
<Route path="/login" element={<LoginSignUp />} />
</Routes>
<Footer />
</Router>
);
}
export default App;
In your App.js you can declare the protected route like this
<Route path="/account" element={ <ProtectedRoute /> } >
<Route path="/account" element={ <Profile /> } >
</Route>
You can use Outlet of react-router v6 for passing the Component
const ProtectedRoute = ({ element: Element, ...rest }) => {
const { loading, isAuthenticated, user } = useSelector(state => state.user);
if (loading) {
return <h2>Loading...</h2>
}
return isAuthenticated ? <Outlet /> : <Navigate to="/login" />;
}
# Sayedul Karim.
I have a better and more concise way for this, An example of the code is below.
<Routes>
<Route element={<App />}>
{isAuthenticated ? (
<>
<Route path="/*" element={<PrivateRoutes />} />
<Route
index
element={<Navigate to="/account" />}
/>
</>
) : (
<>
<Route path="auth/*" element={<AuthPage />} />
<Route path="*" element={<Navigate to="/auth" />} />
</>
)}
</Route>
</Routes>
In this way, you don't have to make any private component instead just make a component for private routes where the routes are defined.
The PrivateRoutes component will be like this
<Routes>
<Route>
{/* Redirect to account page after successful login */}
{/* Pages */}
<Route path="auth/*" element={<Navigate to="/account" />} />
<Route path="account" element={<Account />} />
</Routes>
If any query further, feel free to ask....
I'm not sure, but you haven't pass any "element" prop to your ProtectedRoute component. You pass Profile component as children, so try render children instead of element in ProtectedRoute if you want your code to work like this.
I believe that you might want not to nest those routes, so also you might want to try use ProtectedRoute as Route in your router, I'm talking about something like this
<Routes>
...
<ProtectedRoute path="/account" element={<Profile />} />
...
</Routes>
UPDATE
It might show you this error because your Route is conditionally rendered, so try to handle loading state in some other way, maybe something like this
return (
<Route
{...rest}
render={(props) => {
if(!isAuthenticated) {
return redirect("/login")
}
if(loading) {
return <LoadingComponent />
}
return <Element {...props} />
}}
/>
)
I have an authentication system, and I want to show different <Routes> with different available paths considering from login state.
I uesd <Navigate/> element for redirection from hidden pages depending login state. But there is a problem. <Navigate/> redirects without considering the state.
For example, when I logged in and try to open Login page I must redirects to a Main page, and when I don't logged in and try to open profile I must redirect to Login Page. And when I try to open any of this pages I automaticly redirects to Main page.
routes.jsx:
import React from 'react';
import {
Routes,
Route,
Navigate
} from 'react-router-dom';
import Profile from './pages/Profile/Main/Profile';
import Login from './pages/Auth/Login/Login';
import Register from './pages/Auth/Register/Register';
import Main from './pages/Main/Main';
import { Loans } from './pages/Profile/Active/Loans';
import ErrorPage from './pages/errorPage/ErrorPage';
export const useRoutes = isAuthenticated => {
if(isAuthenticated){
return (
<Routes>
<Route path='/profile' exact>
<Route index path=":id" element={<Profile/>}/>
<Route path="loans" element={<Loans/>} exact/>
</Route>
<Route path='/' exact element={<Main/>}/>
<Route
path="*"
element={<ErrorPage/>}
/>
<Route
path="/auth/*"
element={<Navigate to="/" replace />}
/>
</Routes>
);
} else {
return (
<Routes>
<Route path='/auth' exact>
<Route path='login' element={<Login/>} exact />
<Route path="register" exact element={<Register/>}/>
<Route
path=""
element = {
<Navigate to="login" replace />
}
/>
</Route>
<Route path='/' exact element={<Main/>}/>
<Route
path="/profile/*"
element={<Navigate to="/auth/login" replace />}
/>
<Route
path="*"
element={<ErrorPage/>}
/>
</Routes>
)
}
}
App.jsx:
import {
BrowserRouter
} from 'react-router-dom';
import {useRoutes} from './routes';
import 'materialize-css';
import { useAuth } from './hooks/auth.hook';
import { AuthContext } from './context/auth.context';
function App() {
const {token, userId, login, logout} = useAuth();
const isAuthenticated = !!token;
const routes = useRoutes(isAuthenticated);
return (
<AuthContext.Provider value = {{
token, login, logout, userId, isAuthenticated
}}>
<BrowserRouter>
<div className="container">
{routes}
</div>
</BrowserRouter>
</AuthContext.Provider>
);
}
export default App;
One issue that may be causing this is you check authentication based on whether the token exists. Debug the output of that variable to see if it is cleared correctly when you log out. Next, you are determining authentication once inside of App(), fetching the routes from useRoutes(), and then rendering the app without ever checking again if the authentication is still valid. A better approach would be something like this:
const auth = useAuth();
return ({auth.isAuthenticated ? (
<Fragment>
<Link to="/account">Account ({auth.user.email})</Link>
<Button onClick={() => auth.signout()}>Signout</Button>
</Fragment>
) : (
<Link to="/signin">Signin</Link>
)});
I'm having some kind of trouble when I'm using Router in App.js
I'm getting a blank page when I am using, I tried a lot but couldn't found a way to solve the issue.
<GuestRoute path="/Authenticate" element={<Authenticate />}>
</GuestRoute>
it is working fine with
<Route path="/Authenticate" element={<Authenticate />}>
</Route>
but I have to use GuestRoute.
Given below is the whole code:
App.js
import "./App.css";
import {BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
import React from "react"
import Navigation from "./components/shared/Navigation/Navigation";
import Home from "./Pages/Home/Home";
import Register from "./Pages/Register/Register";
import Login from "./Pages/Login/Login";
import Authenticate from "./Pages/Authenticate/Authenticate";
const isAuth = true;
function App() {
return (
<div className="App">
<Router>
<Navigation />
{/* switch(prev. versions) ----> Routes (new versions)) */}
<Routes>
<Route exact path="/" element={<Home />} >
</Route>
<GuestRoute path="/Authenticate" element={<Authenticate />}>
</GuestRoute>
</Routes>
</Router>
</div>
);
}
const GuestRoute = ({children,...rest}) => {
return(
<Route {...rest}
render={({location})=>{
return isAuth ? (
<Navigate to={{
pathname: '/rooms',
state: {from: location}
}}
/>
):(
children
);
}}
></Route>
);
};
export default App;
react-router-dom#6 doesn't use custom route components. The new pattern used in v6 are either wrapper components or layout route components.
Wrapper component example:
const GuestWrapper = ({ children }) => {
... guest route wrapper logic ...
return (
...
{children}
...
);
};
...
<Router>
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route
path="/Authenticate"
element={(
<GuestWrapper>
<Authenticate />
</GuestWrapper>
)}
/>
</Routes>
</Router>
Layout route component example:
import { Outlet } from 'react-router-dom';
const GuestLayout = () => {
... guest route wrapper logic ...
return (
...
<Outlet /> // <-- nested routes render here
...
);
};
...
<Router>
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route element={<GuestLayout>}>
<Route path="/Authenticate" element={<Authenticate />} />
... other GuestRoute routes ...
</Route>
</Routes>
</Router>
I tried creating a private route using react-router-dom v6 as shown below in React JS
import React from 'react';
import {BrowserRouter as Router, Routes, Route} from 'react-router-dom';
import * as ROUTES from './constants/routes';
import { Home, Signin, Signup, Browse } from './pages';
import { IsUserRedirect, ProtectedUserRedirect } from './helpers/routes';
function App() {
const user=null;
return (
<>
<Router>
<Routes>
<Route exact path={ROUTES.HOME} element={<IsUserRedirect user={user} path={ROUTES.BROWSE} />}>
<Route element={<Home />} />
</Route>
<Route exact path={ROUTES.BROWSE} element={<ProtectedUserRedirect user={user} path={ROUTES.SIGN_IN} />}>
<Route element={<Browse />} />
</Route>
<Route exact path={ROUTES.SIGN_IN} element={<IsUserRedirect user={user} path={ROUTES.BROWSE} />}>
<Route element={<Signin />} />
</Route>
<Route exact path={ROUTES.SIGN_UP} element={<IsUserRedirect user={user} path={ROUTES.BROWSE} />}>
<Route element={<Signup />} />
</Route>
</Routes>
</Router>
</>
);
}
export default App;
and the helper components are implemented as shown below
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';
export const IsUserRedirect = ({path, user, children}) => {
console.log(Boolean(user))
return (
user?<Navigate to={path} replace />:<Outlet />
)
}
export const ProtectedUserRedirect = ({path, user, children}) => {
console.log(Boolean(user))
return (
user?<Outlet />:<Navigate to={path} replace />
)
}
NO ERROR AT TERMINAL AND CONSOLE but I'm not getting any output. The components seems to not rendering properly. Could you please me how to write better private route in v6 of router-dom. Reference: https://dev.to/iamandrewluca/private-route-in-react-router-v6-lg5
THANKS IN ADVANCE
I am using firebase auth for my React js project. Aim - When the user goes to the path - '/home' , it should check whether the user is logged in or not. If not logged in, redirect to the path - '/' ,or else render the component "Home". But, when I run the code, the functions are working properly but, the component is not rendering on the screen.
Code of App.js -
function App() {
var users;
function checkUserLoggedIn() {
firebase.auth().onAuthStateChanged(function (user) {
users = user;
console.log(users);
users ? <Home /> : <Redirect to="/" />;
});
}
return (
<div className="app">
<Router>
<Switch>
<Route exact path="/">
<Welcome />
</Route>
<Route path="/home">{checkUserLoggedIn()}</Route>
</Switch>
</Router>
</div>
);
}
Any idea why this is not working ?
Thanks !
create a Dictionary file route
and add three files
index.js
publicRoute.js
privateRoute.js
in index.js
/// index.js
import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import PrivateRoutes from './PrivateRoutes'
import PublicRoutes from './PublicRoutes';
function Routes() {
const { pathname } = useLocation();
const[isUserLoggedIn, setLoggedIn] = React.useState(false)
useEffect(() => {
firebase.auth().onAuthStateChanged(function (user) {
users = user;
if(users){
setLoggedIn(true)
}
}, [pathname]);
return isUserLoggedIn ? <PrivateRoutes /> : <PublicRoutes />;
}
export default Routes;
And in publicRoutes.js
// publicRoute.js
import React, { Component } from 'react';
import { HashRouter, Redirect, Route, Switch } from 'react-router-dom';
const loading = (
<div className="pt-3 text-center">
<div className="sk-spinner sk-spinner-pulse"></div>
</div>
)
// Pages
const Login = React.lazy(() => import('../views/pages/login/Login'));
const Register = React.lazy(() => import('../views/pages/register/Register'));
class PublicRoutes extends Component {
render() {
return (
<HashRouter>
<React.Suspense fallback={loading}>
<Switch>
<Route exact path="/register" name="Register Page" render={props => <Register {...props}/>} />
<Route path="/login" name="Login Page" render={props => <Login {...props}/>} />
<Route exact path="/register" name="Register Page" render={props => <Register {...props}/>} />
<Redirect to='/login' />
</Switch>
</React.Suspense>
</HashRouter>
);
}
}
export default PublicRoutes;
In Private Route
/// privateRoute.js
import React, { Component } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import '../scss/style.scss';
const loading = (
<div className="pt-3 text-center">
<div className="sk-spinner sk-spinner-pulse"></div>
</div>
)
// Containers
const TheLayout = React.lazy(() => import('../containers/TheLayout'));
// Pages
const Page404 = React.lazy(() => import('../views/pages/page404/Page404'));
const Page500 = React.lazy(() => import('../views/pages/page500/Page500'));
class PrivateRoutes extends Component {
render() {
return (
<HashRouter>
<React.Suspense fallback={loading}>
<Switch>
<Route exact path="/404" name="Page 404" render={props => <Page404 {...props}/>} />
<Route exact path="/500" name="Page 500" render={props => <Page500 {...props}/>} />
<Route path="/" name="Home" render={props => <TheLayout {...props}/>} />
</Switch>
</React.Suspense>
</HashRouter>
);
}
}
export default PrivateRoutes;