check authenticated user in ProtectedRouter component in react using react router v6 - javascript

my app.jsx
import axios from "axios";
import { createContext, useState } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import NavBar from "./components/Navbar";
import ProtectedRoute from "./components/ProtectedRoute";
import Home from "./pages/Home";
import Login from "./pages/Login";
import MyBlogs from "./pages/MyBlogs";
import Profile from "./pages/Profile";
import Signup from "./pages/Signup";
export const AuthContext = createContext();
const App = () => {
const [loggedIn, setLoggedIn] = useState(
Boolean(sessionStorage.getItem("loggedIn"))
);
const VUserData = sessionStorage.getItem("userData");
const [userData, setUserData] = useState(
VUserData ? JSON.parse(VUserData) : null
);
function getUserData() {
return axios
.get("/api/user")
.then((res) => {
return Promise.resolve(res.data);
})
.catch((err) => {
return Promise.reject(err.response);
});
}
return (
<BrowserRouter>
<AuthContext.Provider
value={{
loggedIn,
setLoggedIn,
userData,
setUserData,
getUserData,
}}
>
<Routes>
<Route path="/" element={<NavBar />}>
<Route index element={<Home />} />
<Route path="login" element={<Login />} />
<Route path="signup" element={<Signup />} />
<Route
path="profile"
element={
<ProtectedRoute>
<Profile />
</ProtectedRoute>
}
/>
<Route
path="my-blogs"
element={
<ProtectedRoute>
<MyBlogs />
</ProtectedRoute>
}
/>
</Route>
</Routes>
</AuthContext.Provider>
</BrowserRouter>
);
};
export default App;
my ProtectedRoute.jsx
import { useContext } from "react";
import { Navigate, useLocation } from "react-router-dom";
import { AuthContext } from "../app";
const ProtectedRoute = ({ children, ...rest }) => {
const { loggedIn, getUserData } = useContext(AuthContext);
const location = useLocation();
if (loggedIn) {
getUserData()
.then((res) => {
return children;
})
.catch((res) => {
return (
<Navigate
to="/login"
replace
state={{ path: location.pathname }}
/>
);
});
} else {
return (
<Navigate to="/login" replace state={{ path: location.pathname }} />
);
}
};
export default ProtectedRoute;
my home.jsx
import React from "react";
import { Outlet } from "react-router-dom";
import NavBar from "../components/Navbar";
const Home = () => {
return (
<React.Fragment>
<NavBar />
<Outlet />
</React.Fragment>
);
};
export default Home;
My problem is after successful login, the profile page not rendering. It's just a blank white page but if I replacegetUserData() and the whole promise resolve with just return children; it's in ProtectedRoute.jsx it's working fine why is that?
how could I check whether the user is logged or not by requesting to the backend in ProtectedRoute.jsx

Related

Component is not rendering completely on the page. React

I'm doing fullstack using react and express js including JWT.
The page is not rendering the complete component I imported, it only renders the text but not the functions within it. What I'm trying to do is display the username on the page.
I appreciate any help!
This is my UserProvider.js
import axios from "axios";
import UserContext from "./UserContext";
import React from "react";
import { useEffect, useState } from "react";
export const UserProvider = (props) => {
const baseUrl = "http://localhost:3000/api/users/";
const [ user, setUser ] = useState([]);
useEffect(() => {
async function fetchData() {
await getAllUsers();
}
fetchData();
}, []);
function getAllUsers() {
return axios.get(baseUrl).then(response => setUser(response.data))
};
function createUser(username, password, firstName, lastName) {
let user = { username, password, firstName, lastName };
return axios.post(baseUrl, user)
.then(response => {
return new Promise(resolve => resolve(response.data));
}
);
}
function signInUser(username, password) {
let user = { username, password };
return axios.post(`${baseUrl}/login`, user)
.then(response => {
localStorage.setItem('myPostsToken', response.data.token)
return new Promise(resolve => resolve(response.data));
}
);
}
return (
<UserContext.Provider value={{
user,
createUser,
signInUser
}}>
{ props.children }
</UserContext.Provider>
)
}
This is my UserList.js
import React, { useContext, useState } from 'react';
import '../App.css'
import UserContext from '../contexts/UserContext';
function UsersList(props) {
return (
<UserContext.Consumer>
{
({ user }) => {
return <div>
<h3>Welcome back </h3>
<div>
{user.map((u) => {
console.log(user)
return (
<div>
<div>
<h2>{u.name}</h2>
<p>{"user's name goes here"}</p>
</div>
</div>
)
})}
</div>
</div>
}
}
</UserContext.Consumer>
);
}
export default UsersList;
This is my UserContext.js
import React from "react";
const UserContext = React.createContext();
export default UserContext;
This is my App.js
import React from 'react';
import { Route, BrowserRouter, Routes, Link } from 'react-router-dom'
import SignIn from './components/SignIn'
import SignUp from './components/SignUp'
import PostsList from './components/PostsList'
import NewPosts from './components/NewPosts'
import { PostsProvider } from './contexts/PostsProvider';
import { UserProvider } from './contexts/UserProvider';
import { EditPosts } from './components/EditPosts';
import './App.css'
import NavBar from './components/NavBar';
import UsersList from './components/UsersList'
function App() {
return (
<div className='app'>
<NavBar />
<UserProvider>
<PostsProvider>
<div>
<BrowserRouter>
<Routes>
<Route exact path="/" element={ <SignIn /> } />
<Route path="/signin" element={ <SignIn /> } />
<Route path="/signup" element={ <SignUp /> } />
<Route path="/posts/new" element={ <NewPosts /> } />
<Route path="/postsList" element={ <PostsList /> } />
<Route path="/edit/:id" element={ <EditPosts /> } />
<Route path="/users/" element={ <UsersList /> } />
</Routes>
</BrowserRouter>
</div>
</PostsProvider>
</UserProvider>
</div>
);
}
export default App;

Uncaught TypeError: Cannot read properties of undefined (reading 'pathname') , this error showed while redirecting pages using function [duplicate]

This question already has answers here:
How to create a protected route with react-router-dom?
(5 answers)
Closed 9 months ago.
This code is using if-and condition , if a user is signed-in or just signed-up, then he can stay in browse page otherwise he will be send to the sign-in page and etc.
import React from 'react';
import { Route } from 'react-router-dom';
import {Navigate} from "react-router";
export function IsUserRedirect({ user, loggedInPath, children, ...rest }) {
return (
<Route
{...rest}
render={() => {
if (!user) {
return children;
}
if (user) {
return (
<Navigate
to={{
pathname: loggedInPath,
}}
/>
);
}
return null;
}}
/>
);
}
export function ProtectedRoute({ user, children, ...rest }) {
return (
<Route
{...rest}
render={({ location }) => {
if (user) {
return children;
}
if (!user) {
return (
<Navigate
to={{
pathname: 'signin',
state: { from: location },
}}
/>
);
}
return null;
}}
/>
);
}
Calling the above function:But is showing the errror {Uncaught TypeError: Cannot read properties of undefined (reading 'pathname')}
import React from 'react';
import { BrowserRouter, Router, Routes, Route } from 'react-router-dom';
import { Home, Browse } from './pages';
import * as ROUTES from './constants/routes';
import { IsUserRedirect, ProtectedRoute } from './helpers/routes';
import { useAuthListener } from './hooks';
import SignIn from "./pages/signin";
import SignUp from "./pages/signup";
export function App() {
const { user } = useAuthListener();
return (
<Router>
<Routes>
<IsUserRedirect user={user} loggedInPath={ROUTES.BROWSE} path={ROUTES.SIGNIN}>
<SignIn />
</IsUserRedirect>
<IsUserRedirect user={user} loggedInPath={ROUTES.BROWSE} path={ROUTES.SIGNUP}>
<SignUp />
</IsUserRedirect>
<ProtectedRoute user={user} path={ROUTES.BROWSE}>
<Browse />
</ProtectedRoute>
<IsUserRedirect user={user} loggedInPath={ROUTES.BROWSE} path={ROUTES.HOME}>
<Home />
</IsUserRedirect>
</Routes>
</Router>
);
}
[enter image description here][2]
It is solved
import React from 'react';
import { BrowserRouter, Router, Route } from 'react-router-dom';
import { Home, Browse } from './pages';
import * as ROUTES from './constants/routes';
import { IsUserRedirect, ProtectedRoute } from './helpers/routes';
import { useAuthListener } from './hooks';
import SignIn from "./pages/signin";
import SignUp from "./pages/signup";
import {Routes, useRoutes} from "react-router";
export function App() {
const { user } = useAuthListener();
return (
<BrowserRouter>
<Routes>
<Route path="/browse" element = {
<ProtectedRoute>
<Browse />
</ProtectedRoute>} />
<Route path="/signup" element = {
<IsUserRedirect>
<SignUp />
</IsUserRedirect>} />
<Route path="/signin" element = {
<IsUserRedirect>
<SignIn />
</IsUserRedirect>} />
<Route path="/home" element = {
<IsUserRedirect>
<Home />
</IsUserRedirect>} />
</Routes>
</BrowserRouter>
);
}
import React from 'react';
import {Navigate} from "react-router";
import {useAuthListener} from "../hooks";
export function ProtectedRoute({children}) {
const auth =useAuthListener();
return auth ? children : <Navigate to="/signin" />;
}
export function IsUserRedirect({ loggedInPath,children }) {
const auth =useAuthListener();
return auth ? children : <Navigate to="/browse" />;
}

Facing issue with Custom Route with latest react-router-dom version 6

Recently, I am facing issue with Custom Route with latest react-router-dom version 6 in my code.
I have created custom route for authorized if user is not login then it will redirect to sign in page. It was working with previous react router version but now it's got broke with latest one.
I am posting the code below.
Getting below error message as well.
[UserRoute] is not a component. All component children of must be a Route or <React.Fragment>
LoadingToRedirect.js
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
const LoadingToRedirect = () => {
const [count, setCount] = useState(5);
const navigate = useNavigate();
useEffect(() => {
const interval = setInterval(() => {
setCount((currentCount) => --currentCount);
}, 1000);
count === 0 && navigate("/login");
return () => clearInterval(interval);
}, [count, navigate]);
return (
<div>
<p>Redirecting you in {count} seconds</p>
</div>
);
};
export default LoadingToRedirect;
UserRoute.js
import React from "react";
import { Route, Routes } from "react-router-dom";
import { useSelector } from "react-redux";
import LoadingToRedirect from "./LoadingToRedirect";
const UserRoute = ({ children, ...rest }) => {
const { currentUser } = useSelector((state) => state.user);
return currentUser ? <Route {...rest} /> : <LoadingToRedirect />;
};
export default UserRoute;
App.js
import React, { useEffect, Fragment } from "react";
import "./App.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import Login from "./pages/Login";
import Register from "./pages/Register";
import UserRoute from "./components/UserRoute";
import { useDispatch } from "react-redux";
import { auth } from "./firebase";
import { setUser } from "./redux/actions";
import Header from "./components/Header";
import AddEdit from "./pages/AddEdit";
function App() {
const dispatch = useDispatch();
useEffect(() => {
auth.onAuthStateChanged((authUser) => {
if (authUser) {
dispatch(setUser(authUser));
} else {
dispatch(setUser(null));
}
});
}, [dispatch]);
return (
<BrowserRouter>
<div className="App">
<Header />
<ToastContainer position="top-center" />
<Fragment>
<Routes>
<UserRoute path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<UserRoute path="/addContact" element={<AddEdit />} />
</Routes>
</Fragment>
</div>
</BrowserRouter>
);
}
export default App;
In react-router v6, the Routes component allows only Route children.
In UserRoute.js if there's no user you are returning LoadingToRedirect:
return currentUser ? <Route {...rest} /> : <LoadingToRedirect />;
You can try changing this to:
const UserRoute = ({ children, path, element }) => {
const { currentUser } = useSelector((state) => state.user);
return <Route path={path} element={ currentUser ? element : <LoadingToRedirect />} />;
};

React.js how do i show pages depending on the status?

I want to implement a case where when users are logged in that they need to able to access the AppStack and the AuthStack. And if they not logged in, only the AuthStack will be accessible. Also when they try to access the AppStack they should get redirected. In react native I could handle this with a AuthStack and if something changed the user status he could see the one stack or the other one. But I don't know how to do it with reactjs
AuthNavigator
import React, { useState, useEffect } from 'react';
import app from './firebase';
import AuthStack from './stacks/AuthStack';
import AppStack from './stacks/AppStack';
function AuthNavigator() {
const [initializing, setInitializating] = useState(true);
const [user, setUser] = useState(true);
function onAuthStateChanged(result) {
setUser(result);
if (initializing) setInitializating(false);
if (result) {
app
.auth()
.currentUser.getIdToken(/* force Refresh */ true)
.then((idToken) => {
result.idToken = idToken;
setUser(result);
})
.catch((error) => {
console.log(error.message);
});
}
}
useEffect(() => {
const authSubscriber = app.auth().onAuthStateChanged(onAuthStateChanged);
return authSubscriber;
});
if (initializing) {
return null;
}
return user ? <AppStack user={user} /> : <AuthStack user={user} />;
}
export default AuthNavigator;
AppStack here i tried it like if there is a user then you can render the appStack else you get redirected to the authstack.
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import { Redirect } from 'react-router';
import Overview from '../pages/app/Overview';
import Sidebar from '../components/Sidebar/Sidebar';
function AppStack({ user }) {
return this.props.user ? (
<Router>
<Switch>
<Sidebar user={user} />
<Route path="/app-melior/overview" exact component={Overview}></Route>
</Switch>
</Router>
) : (
<Redirect path="/auth/signin"></Redirect>
);
}
export default AppStack;
AuthStack
import React from 'react';
import Navbar from '../components/Navbar/Navbar';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import SignIn from '../pages/auth/SignIn';
function AuthStack({ user, app }) {
return (
<>
<Router>
<Switch>
<Route path="/auth">
<Navbar />
<Route path="/auth/signin" app={app} exact component={SignIn} />
</Route>
</Switch>
</Router>
</>
);
}
export default AuthStack;
I usually create a Private route and hanlde it like this
import React, { useState, useEffect } from 'react';
import app from './firebase';
import AuthStack from './stacks/AuthStack';
import AppStack from './stacks/AppStack';
function AuthNavigator() {
const [initializing, setInitializating] = useState(true);
const [user, setUser] = useState(true);
const PrivateRoute = ({ component, ...rest }) => {
return (
<Route
{...rest}
render={(props) =>
user ? (
<Component {...props}></Component>
) : (
<Redirect to="/auth"></Redirect>
)
}
></Route>
);
};
function onAuthStateChanged(result) {
setUser(result);
if (initializing) setInitializating(false);
if (result) {
app
.auth()
.currentUser.getIdToken(/* force Refresh */ true)
.then((idToken) => {
result.idToken = idToken;
setUser(result);
})
.catch((error) => {
console.log(error.message);
});
}
}
useEffect(() => {
const authSubscriber = app.auth().onAuthStateChanged(onAuthStateChanged);
return authSubscriber;
});
if (initializing) {
return null;
}
return
<Router>
<Switch>
<PrivateRoute path="/app>
<Sidebar user={user} />
<PrivateRoute path="/app-melior/overview" exact component={Overview}></PrivateRoute>
</PrivateRoute>
<Route path="/auth">
<Navbar />
<Route path="/auth/signin" app={app} exact component={SignIn} />
</Route>
</Switch>
</Router>;
}
export default AuthNavigator;

How to redirect to a different page after authenticated with React

I have bought a template in envato which is quite complex, I know a bit of react, I am not an expert yet, however I managed to integrate Azure AD Authentication into the app.
I used this procedure:
https://github.com/salvoravida/react-adal
My app is like this:
DashApp.js
import React from "react";
import { Provider } from "react-redux";
import { store, history } from "./redux/store";
import PublicRoutes from "./router";
import { ThemeProvider } from "styled-components";
import { LocaleProvider } from "antd";
import { IntlProvider } from "react-intl";
import themes from "./settings/themes";
import AppLocale from "./languageProvider";
import config, {
getCurrentLanguage
} from "./containers/LanguageSwitcher/config";
import { themeConfig } from "./settings";
import DashAppHolder from "./dashAppStyle";
import Boot from "./redux/boot";
const currentAppLocale =
AppLocale[getCurrentLanguage(config.defaultLanguage || "english").locale];
const DashApp = () => (
<LocaleProvider locale={currentAppLocale.antd}>
<IntlProvider
locale={currentAppLocale.locale}
messages={currentAppLocale.messages}
>
<ThemeProvider theme={themes[themeConfig.theme]}>
<DashAppHolder>
<Provider store={store}>
<PublicRoutes history={history} />
</Provider>
</DashAppHolder>
</ThemeProvider>
</IntlProvider>
</LocaleProvider>
);
Boot()
.then(() => DashApp())
.catch(error => console.error(error));
export default DashApp;
export { AppLocale };
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import DashApp from './dashApp';
import registerServiceWorker from './registerServiceWorker';
import 'antd/dist/antd.css';
import { runWithAdal } from 'react-adal';
import { authContext } from './adalConfig';
const DO_NOT_LOGIN = false;
runWithAdal(authContext, () => {
ReactDOM.render(<DashApp />, document.getElementById('root'));
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./dashApp.js', () => {
const NextApp = require('./dashApp').default;
ReactDOM.render(<NextApp />, document.getElementById('root'));
});
}
},DO_NOT_LOGIN);
registerServiceWorker();
and router.js
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import { connect } from 'react-redux';
import App from './containers/App/App';
import asyncComponent from './helpers/AsyncFunc';
const RestrictedRoute = ({ component: Component, isLoggedIn, ...rest }) => (
<Route
{...rest}
render={props => isLoggedIn
? <Component {...props} />
: <Redirect
to={{
pathname: '/signin',
state: { from: props.location },
}}
/>}
/>
);
const PublicRoutes = ({ history, isLoggedIn }) => {
return (
<ConnectedRouter history={history}>
<div>
<Route
exact
path={'/'}
component={asyncComponent(() => import('./containers/Page/signin'))}
/>
<Route
exact
path={'/signin'}
component={asyncComponent(() => import('./containers/Page/signin'))}
/>
<RestrictedRoute
path="/dashboard"
component={App}
isLoggedIn={isLoggedIn}
/>
</div>
</ConnectedRouter>
);
};
export default connect(state => ({
isLoggedIn: state.Auth.get('idToken') !== null,
}))(PublicRoutes);
The authentication is working fine, but its redirected to a custom login page the template has, I want the redirect to be to /dashboard instead.
Thats the question, should be easy, but new to react routing
Please Give a try. (I'm not 100% sure - I just made a guess from the given code)
router.js
const PublicRoutes = ({ history, isLoggedIn }) => {
return (
<ConnectedRouter history={history}>
<div>
<Route
exact
path={'/'}
render={() => <Redirect to="/dashboard" />}
/>
<Route
exact
path={'/signin'}
component={asyncComponent(() => import('./containers/Page/signin'))}
/>
<RestrictedRoute
path="/dashboard"
component={App}
isLoggedIn={isLoggedIn}
/>
</div>
</ConnectedRouter>
);
};

Categories

Resources