React Router doesn't display sign in if there is user - javascript

I have a main routes component like this
import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import PrivateRoute from './PrivateRoute'
import AdminPanel from './pages/AdminPanel/AdminPanel'
import SignIn from './pages/SignIn'
import '../assets/stylesheets/styles.scss'
const AppContent = props => <Router>
<div>
<PrivateRoute path='/' component={AdminPanel} />
<Route path='/sign-in' component={SignIn} />
</div>
</Router>
export default AppContent
Here is the PrivateRoute.jsx
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
import { connect } from 'react-redux'
const PrivateRoute = ({ component: Component, currentUser, ...rest }) => (
<Route
{...rest}
render={props =>
currentUser ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/sign-in',
state: { from: props.location }
}}
/>
)
}
/>
)
export default connect(({ currentUser }) => ({ currentUser }))(PrivateRoute)
so if currentUser is null it redirects to /sign-in which is perfectly fine. However the problem is if there is currentUser and I go to /sign-in I still get the AdminPanel component.
Here is the currentUser reducer and AdminPanel component in case needed.
import { SIGNIN, SIGNOUT } from '../actions/types'
// so here the default state is null, however if I change it to `{}` which will mean there is a user then I am not able to go to the `/sign-in`
export default (state = null, action) => {
switch (action.type) {
case SIGNIN:
return action.payload
case SIGNOUT:
return null
default:
return state
}
}
And AdminPanel
import React, { Component } from 'react'
import { Route, Switch } from 'react-router-dom'
import Box, { Container } from 'react-layout-components'
import LeftMenu from '../../components/AdminPanel/LeftMenu'
import Header from '../../components/AdminPanel/Header'
import Home from './Home'
import Dashboard from './Dashboard'
import Categories from './Categories'
import Partners from './Partners'
import Users from './Users'
import TeamMembers from './TeamMembers'
import Settings from './Settings'
import Help from './Help'
class AdminPanel extends Component {
render () {
return (
<Box>
<Container minWidth={300}>
<LeftMenu />
</Container>
<Container padding='15px' width='100%'>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/dashboard' component={Dashboard} />
<Route exact path='/categories' component={Categories} />
<Route exact path='/partners' component={Partners} />
<Route exact path='/users' component={Users} />
<Route exact path='/team-members' component={TeamMembers} />
<Route exact path='/settings' component={Settings} />
<Route exact path='/help' component={Help} />
</Switch>
<Header />
</Container>
</Box>
)
}
}
export default AdminPanel
And SignIn component is just a plain class based component
import React, { Component } from 'react'
class SignIn extends Component {
render () {
return (
<div>SignIn</div>
)
}
}
export default SignIn

Related

Private routes in "react-router-dom": "6.0.0-beta.0"

Please help me
When the Route is not inside <Routes> it gives an error:
Error: A is only ever to be used as the child of element, never rendered directly. Please wrap your in a
When it is inside <Routes> it give an error as:
Error: [Abc] is not a <Route> component. All component children of must be a <Route> or <React.Fragment>
Pls help me to resolve this situation? Or any suggestion.
Tried this but one of the above error in both cases.
As this does not generate an error, however my child component of the private route does not render.
import React from 'react'
import './App.css'
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Header from './components/Header'
import Home from './components/Home'
import Login from './components/Login'
import ProtectedRoute from './components/Helper/ProtectedRoute';
import { UserStorage } from './UserContext';
import User from './components/User';
const App = () => {
return (
<div>
<BrowserRouter>
<UserStorage>
<>
<Header />
<Routes>
<Route path="/" element={<Home />} />
<Route path="login/*" element={<Login />} />
<Route path='/conta' element={<ProtectedRoute/>}>
<Route path='/conta' element={<User/>}/>
</Route>
</Routes>
</>
</UserStorage>
</BrowserRouter>
</div>
)
}
export default App;
ProtectedRoute
import React from 'react';
import { UserContext } from '../../UserContext';
import {Routes, Route, Navigate } from 'react-router-dom';
const ProtectedRoute = (props) => {
const { login } = React.useContext(UserContext);
if (login === true) return (
<Routes>
<Route {...props} />
</Routes>
);
else if (login === false) return <Navigate to="/login" />;
else return null;
};
export default ProtectedRoute;
With layout wrapper components like ProtectedRoute that renders nested Route components then you need to ensure it is rendering an Outlet for them to be rendered into.
Outlet
import React from 'react';
import { UserContext } from '../../UserContext';
import {Routes, Route, Navigate } from 'react-router-dom';
const ProtectedRoute = () => {
const { login } = React.useContext(UserContext);
if (login === undefined) return null;
return login
? <Outlet /> // <-- nested Route components rendered here
: <Navigate to="/login" replace />;
};
...
<Route path='/conta' element={<ProtectedRoute/>}>
<Route path='/conta' element={<User/>}/> // <-- rendered into outlet
</Route>

React-router-dom Protected Routes are not working

Protected Routes.js:
In protected routes you can see I'm using directly false in if statement but I'm still able to see that page why?
import React from 'react';
import { Route } from 'react-router-dom';
// import Auth from './User/Auth';
import Error401 from './Error/401';
// create a component for protected route
console.log('Routes.js');
export const ProtectedRoute = ({ element: Element, ...rest }) => {
console.log("Function Called")
return (
<Route {...rest} render={props => {
if(false){
return <Element {...props} />
}else{
return <Error401 />
}
}
} />
)
}
App.js:
This is app.js where I'm using protected routes component
import './App.css';
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Layout } from 'antd';
import { MoneyCollectOutlined } from '#ant-design/icons';
import Login from './Components/User/Login';
import Signup from './Components/User/Signup';
import {ProtectedRoute} from './Components/Routes';
import Error404 from './Components/Error/404';
function App() {
return (
<BrowserRouter>
<Layout style={{minHeight:"100vh"}}>
<Layout.Header>
<h1 style={{color:"white"}} align="center"> <MoneyCollectOutlined/>MoneyG</h1>
</Layout.Header>
<Layout.Content style={{minHeight:"100%"}}>
<Routes>
<ProtectedRoute exact path="/register" element={<Signup/>} />
<ProtectedRoute exact path="/login" element={<Login/>} />
<Route path="*" element={<Error404/>} />
</Routes>
</Layout.Content>
</Layout>
</BrowserRouter>
);
}
export default App;
First, <Routes> elements should only have <Route> elements as children. You should move your protection logic down a layer.
Secondly, the render prop doesn't exist anymore in V6. It was replaced in favor of element. See doc.
Here is how you might tackle it:
<Routes>
<Route exact path="/register" element={(
<ProtectedRoute>
<Signup/>
</ProtectedRoute>
)} />
<Route exact path="/login" element={(
<ProtectedRoute>
<Login/>
</ProtectedRoute>
)} />
<Route path="*" element={<Error404/>} />
</Routes>
And:
const ProtectedRoute = () => {
if (condition) { return <Error401 />; } // You might as well use Navigate here
return children;
};
you can use createContext & useContext
//store/AuthApi.jsx
import { createContext } from "react";
const AuthApi = createContext();
export default AuthApi;
Then define the context app.jsx
import React, from 'react'
import { AllRoutes } from 'routes/Routes';
import { BrowserRouter as Router } from "react-router-dom";
import AuthApi from 'store/AuthApi';
const App = () => {
const [user, setUser] = useState(false);
useEffect(() => {
// you can get user from localStorage or Cookie(js-cookie npm)
//then you can change user state true or false
}, [])
return (
<>
<AuthApi.Provider value={{ user, setUser }}>
<Router>
<AllRoutes />
</Router>
</AuthApi.Provider>
<Toast />
</>
)
}
export default App
then see AllRoutes
//routes/Routes
import React, { useContext } from "react";
import { Routes, Route } from "react-router-dom";
import { SignIn, SignUp, Dashboard } from "pages";
import AuthApi from "store/AuthApi";
export const ProtectedRouting = () => {
return (
<Routes >
<Route path='/' exact element={<Dashboard />} />
// add more protected routes
</Routes>
)
}
export const AuthRouting = () => {
return (
<Routes >
<Route exact={true} path='/sign-in' element={<SignIn />} />
<Route exact={true} path='/sign-up' element={<SignUp />} />
</Routes>
)
}
export const AllRoutes = ()=> {
const context = useContext(AuthApi);
console.log(context.user)
return (
context.user ?
<ProtectedRouting />
: <AuthRouting />
)
}
pages/SignIn.jsx
import React,{ useContext } from 'react';
import AuthApi from "store/AuthApi";
const SignIn = () => {
const context = useContext(AuthApi);
const signInSubmit =(e)=> {
e.preventDefault();
//post request to signin
// if login is successfull then save user or token in cookie or localStorage or something
context?.setUser(true);
//...
}
return (
//signin code here
<form onSubmit={signInSubmit}>
///input here
</form>
)
}
export default SignIn

Why dashboard route is not accessible to me even if I am logged in?

I am using private route in my app to access dashboard. if I am not logged in it worked correctly and redirect me to the sign in page. but even if I am logged in it does not gives access to dashboard. Here is my code.
App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './containers/Home';
import Login from './containers/Login';
import Dashboard from './containers/Dashboard';
import PrivateRoute from './components/PrivateRoute';
import { Provider } from 'react-redux';
import store from './store';
const App = () => (
<Provider store={store}>
<Router>
<Layout>
<Switch>
<Route exact path='/' component={Home} />
<PrivateRoute exact path='/dashboard' component={Dashboard} />
<Route exact path='/login' component={Login} />
</Switch>
</Layout>
</Router>
</Provider>
);
export default App;
PrivateRoute.js
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
const PrivateRoute = ({ component: Component, auth, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (!auth.isAuthenticated) {
return <Redirect to="/login" />;
} else {
return <Component {...props} />;
}
}}
/>
);
const mapStateToProps = (state) => ({
auth: state.auth,
});
export default connect(mapStateToProps)(PrivateRoute);
And if I am logged in on react redux tool my states are these
I noticed even if isAuthanticated becomes true after login but else part of privateRoutes.js never called

React not rendering correctly layout after redirect

I have an app that uses styled-components and material-ui. I have private routes configurated, based on the user role and if the user is not authenticated I should return him to login page. But when that happen the layout do no load.
App.tsx
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core';
import { Provider } from 'react-redux';
import { ToastContainer } from 'react-toastify';
import { PersistGate } from 'redux-persist/integration/react';
import { ThemeProvider as StyledThemeProvider } from 'styled-components';
import Routes from './routes';
import { configureStore } from './store/configure-store';
import GlobalStyle from './styles/globalTheme';
import defaultTheme from './styles/theme/default.theme';
const { store, persistor } = configureStore();
const theme = createMuiTheme({});
function App() {
return (
<Provider store={store}>
<MuiThemeProvider theme={theme}>
<StyledThemeProvider theme={defaultTheme}>
<PersistGate loading={null} persistor={persistor}>
<GlobalStyle />
<Routes />
<ToastContainer />
</PersistGate>
</StyledThemeProvider>
</MuiThemeProvider>
</Provider>
);
}
export default App;
routes.tsx
import React, { memo } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import NotFound from '../components/NotFound';
import Dashboard from '../pages/Dashboard';
import Login from '../pages/Login';
import Register from '../pages/Register';
import { ProtectedRoute } from './permissions-route';
function Routes() {
return (
<BrowserRouter>
<Switch>
<ProtectedRoute
path="/dashboard"
component={Dashboard}
requiredRole={['USER']}
/>
<Route exact path="/" component={Login} />
<Route exact path="/login" component={Login} />
<Route exact path="/cadastro" component={Register} />
<Route exact path="/error" component={NotFound} />
</Switch>
</BrowserRouter>
);
}
export default memo(Routes);
permission-route.tsx
import React from 'react';
import { useSelector } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';
import { RootState } from '../store/configure-store';
interface Teste {
path: any;
component: any;
render?: any;
requiredRole: any;
}
export const ProtectedRoute = ({
path,
component: Component,
render,
requiredRole,
...rest
}: Teste) => {
const userRole = useSelector((state: RootState) => state.user.role);
return (
<Route
path={path}
{...rest}
render={(props) => {
if (requiredRole.includes(userRole)) {
return Component ? <Component {...props} /> : render(props);
}
return <Redirect to="/login" />;
}}
/>
);
};
export default ProtectedRoute;
What happens after redirect occurs
Instead of returning the <Redirect /> component, try window.location.href = "/login";
return (
<Route
path={path}
{...rest}
render={(props) => {
if (requiredRole.includes(userRole)) {
return Component ? <Component {...props} /> : render(props);
}
window.location.href = "/login";
}}
/>
);
This should refresh the page and make it get the proper stylings again
I had a similar issue using MUI and Router.
I found that I was importing different versions of MUI: #mui and #material-ui after replacing #material-ui components and uninstalling it, the issue was resolved.
Most likely this is an issue with conflicting styling.
I suggest checking browser DevTools to see what files/classes are overriding these styles after redirect.

"react-router-dom " router component does not work

I want to use history explicitly. So I know about BrowserRoute but I want to use Route and use history as its property. when I run the program I get this page.enter image description here
This is my AppRouter.js
import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import LoginPage from "../components/LoginPage";
import ExpenseDashboardPage from "../components/ExpenseDashboardPage";
import AddExpensePage from "../components/AddExpensePage";
import EditExpensePage from "../components/EditExpensePage";
import NotFoundPage from "../components/NotFoundPage";
import PublicRoute from "./PublicRoute";
import PrivateRoute from "./PrivateRoute";
export const history = createBrowserHistory();
const AppRouter = () => (
<Router history={history}>
<div>
<Switch>
<PublicRoute path="/" component={LoginPage} exact={true} />
<PrivateRoute path="/dashboard" component={ExpenseDashboardPage} />
<PrivateRoute path="/create" component={AddExpensePage} />
<PrivateRoute path="/edit/:id" component={EditExpensePage} />
<Route component={NotFoundPage} />
</Switch>
</div>
</Router>
);
export default AppRouter;
LoginPage.js
import React from "react";
import { connect } from "react-redux";
import { startLogin } from "../actions/auth";
export const LoginPage = ({ startLogin }) => (
<div>
<button onClick={startLogin}>Login with Google</button>
<button>Amir Hossein Jobeiri</button>
</div>
);
const mapDispatchToProps = (dispatch) => ({
startLogin: () => dispatch(startLogin()),
});
export default connect(undefined, mapDispatchToProps)(LoginPage);
PublicRoute.js
import React from "react";
import { connect } from "react-redux";
import { Route, Redirect } from "react-router-dom";
export const PublicRoute = ({
isAuthenticated,
component: Component,
...rest
}) => (
<Route
{...rest}
component={(props) =>
isAuthenticated ? <Redirect to="/dashboard" /> : <Component {...props} />
}
/>
);
const mapStateToProps = (state) => ({
isAuthenticated: !!state.auth.uid,
});
export default connect(mapStateToProps)(PublicRoute);
PrivateRoute
import React from "react";
import { connect } from "react-redux";
import { Route, Redirect } from "react-router-dom";
import Header from "../components/Header";
export const PrivateRoute = ({
isAuthenticated,
component: Component,
...rest
}) => (
<Route
{...rest}
component={(props) =>
isAuthenticated ? (
<div>
<Header />
<Component {...props} />
</div>
) : (
<Redirect to="/" />
)
}
/>
);
const mapStateToProps = (state) => ({
isAuthenticated: !!state.auth.uid,
});
export default connect(mapStateToProps)(PrivateRoute);
I searched a lot about this problem but I do not get the right answer. Please help if you can.
I changed my "history" version to "4.7.2". It works properly.

Categories