React router dom navigate method is not working properly - javascript

Hei, I am trying to build a simple react app with a navigation feature. The main theme is I have 3 components, App, Test, and AppShell. App component is the default(Initial) component. And what I want is that Every time user goes to App component, my app will redirect to Test component.
The problem I am facing is that my redirection only works when I load the application the first time, after that my redirection is not working.
I am sharing my three components code below along with the index page!
Index page
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Routes,
Route
} from "react-router-dom";
ReactDOM.render(
<Router>
<Routes>
<Route path='/' element={<App />} />
<Route path='/test' element={<Test />} />
</Routes>
</Router>,
document.getElementById('root')
);
function Test() {
return <h1>Test Me</h1>;
}
reportWebVitals();
App Component
import "./App.css";
import AppShell from "./components/core/appShell";
import { useNavigate } from 'react-router-dom';
export default function App(props) {
let navigate = useNavigate();
return <AppShell {...props} navigate={navigate} />;
}
App shell component
import React, { Component } from 'react';
import { Outlet } from "react-router-dom";
class AppShell extends Component {
componentDidMount() {
this.props.navigate('/test');
}
render() {
return (
<div>
<h1>This is app shell</h1>
<Outlet />
</div>
);
}
}
export default AppShell;
I thought the problem is lies within component hooks, so I tried to implement the redirection inside the constructor too, but nothing is working for me!
The basic business problem I am trying to solve here is - A user will be redirected to a login page, every time he/she tries to browse another page regardless of valid login(valid user) could be based on the valid token on local storage
Could anyone say, What I am doing wrong?

Authentication with regards to protected routes is actually pretty trivial in react-router-dom v6
Create a wrapper component that accesses the auth context (local state, redux store, local storage, etc...) and based on the auth status renders an Outlet component for nested routes you want to protect, or a redirect to your auth endpoint.
Example AuthWrapper:
const AuthWrapper = () => {
const location = useLocation();
const token = !!JSON.parse(localStorage.getItem("token"));
return token ? (
<Outlet />
) : (
<Navigate to="/login" replace state={{ from: location }} />
);
};
Uses:
useLocation hook to grab the current location user is attempting to access.
Outlet component for nested protected routes.
Navigate component for declarative navigation, sends the current location in route state so user can be redirected back after authenticating.
Example Usage:
<Router>
<Routes>
<Route element={<AuthWrapper />}>
<Route path="/" element={<App />} />
</Route>
<Route path="/login" element={<Login />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</Router>
Login - In the authentication handler, once authenticated, set the localStorage and navigate to the location that was passed in route state.
function Login() {
const { state } = useLocation();
const navigate = useNavigate();
const { from = "/" } = state || {};
const login = () => {
localStorage.setItem("token", JSON.stringify(true));
navigate(from);
};
return (
<>
<h1>Test Me</h1>
<button type="button" onClick={login}>Log In</button>
</>
);
}

Related

in Switch Route Routing time it's working, but now latest new Routes, Route it not working custom route

in Switch Route Routing time it's working, but now latest new Routes, Route it not working custom route
I have wrapped the navbar page and home page in HomeLayoutHOC
can anyone help me :) how to do this latest version I try but so many things. no result for this
I want 'HomeLayoutHOC " route instead of "Route"
->client\src\App.JSX :
//HOC
import HomeLayoutHOC from "./HOC/Home.Hoc";
import { Route, Routes } from "react-router-dom";
//Component
import Temp from "./Components/temp";
function App() {
return (
<>
<Routes>
<HomeLayoutHOC path="/" exact element={Temp} /> // <--- I want this to work!
// <Route path="/" element={<Temp />} /> // <-- this working fine
</Routes>
</>
);
}
export default App;
result 👇
screenshot!
->client\src\index.jsx :
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import "./index.CSS";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
-> client\src\HOC\Home.Hoc.jsx
import React from "react";
import { Route } from "react-router-dom";
// Layout
import HomeLayout from "../Layout/Home.Layout";
const HomeLayoutHOC = ({ component: Component, ...rest }) => {
return (
<>
<Route
{...rest}
component={(props) => (
<HomeLayout>
<Component {...props} />
</HomeLayout>
)}
/>
</>
);
};
export default HomeLayoutHOC;
->client\src\Layout\Home.Layout.jsx
import React from "react";
// Components
import Navbar from "../Components/Navbar";
const HomeLayout = (props) => {
return (
<>
<Navbar />
<div className="container mx-auto px-4 lg:px-20 ">{props.children}</div>
</>
);
};
export default HomeLayout;
please give me the possible suggestion for the latest router dom (Routes, Route)
wrapping/composing
How can I spread routeProps to make them available to your rendered Component the latest router dom (Routes, Route)
react-router-dom#6 removed the need, and compatibility, for custom route components. It's an invariant violation to render anything other than a Route or React.Fragment component in the Routes component. Custom route components are replaced with the use of either wrapper components on individual routes wrapping the element being rendered, or by layout route components that can wrap any number of nested Route components.
Wrapper components render the children prop
<Route
path="/"
element={(
<Wrapper>
<Componenet />
</Wrapper>
)}
>
Layout Route components render an Outlet component for nested routes to render their element prop into.
<Route element={<Layout />}>
<Route path="/" element={<Componenet />} />
</Route>
You are asking for the Layout Route version since it seems you want to render the Navbar component as part of a greater layout.
HomeLayout
import React from "react";
import { Outlet } from "react-router-dom";
import Navbar from "../Components/Navbar";
const HomeLayout = () => {
return (
<>
<Navbar />
<div className="container mx-auto px-4 lg:px-20 ">
<Outlet />
</div>
</>
);
};
export default HomeLayout;
App
Render HomeLayout on a pathless route as a Layout Route. The nested Route components render their content into the outlet.
import { Route, Routes } from "react-router-dom";
import HomeLayout from "./path/to/HomeLayout";
import Temp from "./Components/temp";
function App() {
return (
<Routes>
<Route element={<HomeLayout />}>
<Route path="/" element={<Temp />} />
... other routes to render with Home layout and Navbar ...
</Route>
... other routes to render without Home layout and Navbar ...
</Routes>
);
}
An important aspect you should notice here is that RRDv6 removed route props, all the old "props" are now only accessible via React hooks in the routed component, i.e. useNavigate, useLocation, useParams, etc. If you are still using React class-based components they won't be able to use React hooks, and since RRDv6 also no longer exports the withRouter Higher Order Component, well, you will need to roll your own. See What happened to withRouter? I need it! for details.

How to solve "Functions are not valid as a React child." error when I try to render a components based on the output of a function?

In my App.js file of the application, I am setting the routes of the app.
This is the code of my App.js file
import React, {useEffect} from "react";
import {Container} from '#material-ui/core';
import {BrowserRouter, Routes, Route, Navigate} from 'react-router-dom';
import { gapi } from 'gapi-script';
import Navbar from "./components/Navbar/Navbar";
import Home from './components/Home/Home';
import Auth from "./components/Auth/Auth";
import MealsPage from "./components/MealsPage/MealsPage";
import WorkoutDetails from "./components/WorkoutDetails/WorkoutDetails";
const App=()=>{
const user=JSON.parse(localStorage.getItem('profile'));
useEffect(() => {
const start = () => {
gapi.auth2.init({
clientId: process.env.REACT_APP_GOOGLE_API_TOKEN,
scope: ""
})
};
gapi.load('client:auth2', start);
})
return(
<BrowserRouter>
<Container maxWidth="xl">
<Navbar/>
<Routes>
<Route path="/" exact ={()=>{<Navigate to="/workouts"/>}}/>
<Route path="/workouts" exact element={<Home/>}/>
<Route path="/workouts/search" exact element={<Home/>}/>
<Route path="/workouts/:id" element={<WorkoutDetails/>}/>
<Route path="/meals" exact element={<MealsPage/>}/>
<Route path="/auth" exact element={()=>{!user? <Auth/>:<Navigate to="/workouts"/>}}/>
</Routes>
</Container>
</BrowserRouter>
);
}
export default App;
I am getting an error that says this:
react-dom.development.js:67
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
I assume it is from the Auth route as it does not specify an element to render when we have that specific route, but it specifies a function. Basically, when the user is logged in, he should not see the auth component because he is already logged in and he should be redirected to the '/workouts' route which is another page in the application.
Could you help me solve this?
Here
element={()=>{!user? <Auth/>:<Navigate to="/workouts"/>}}.
Try it like element={user? <Navigate to="/workouts"/> : <Auth/>} or return component like element={()=>!user? <Auth/>:<Navigate to="/workouts"/>} or
element={()=>{return !user? <Auth/>:<Navigate to="/workouts"/>}}
Looking at the documentation for <Route />, the element prop is meant to be an element - not a function returning an element.
Therefore, you should simply be able to remove the function call and pass the element directly:
<Route
path="/auth"
exact
element={!user ? <Auth/> : <Navigate to="/workouts"/>}
/>

problems on page refresh

I have built an admin panel using react. After logging in to the panel whenever the user refreshes the page, everything disappears, I don't know why its happening.
Its working fine without the signin page but after adding the signin page it doesn't.
Here is the App.js file code where all the Routes are defined.
import React, { useState } from "react";
import { Route, Switch } from "react-router-dom";
import { Link } from "react-router-dom";
import * as FaIcons from "react-icons/fa";
import SideMenu from "./SideMenu";
import Dashboard from "./components/Dashboard";
import Registration_Request from "./components/Registration_Request";
import Users from "./components/Users";
import Seller from "./components/Request Pages/Seller";
import Reseller from "./components/Request Pages/Reseller";
import Sales from "./components/Request Pages/Sales";
import Sellers from "./components/Sellers";
import Character_Upload from "./components/Character_Upload";
import Campaign_Design from "./components/Campaign_Design";
import Levels_Design from "./components/Levels_Design";
import SellingCoins from "./components/SellingCoins";
import SignIn from "./SignIn";
function App() {
let [signedIn, isSignedIn] = useState(false);
return (
<>
<div className="header"></div>
<div className="main-content">
<Switch>
<Route path="/" exact>
<SignIn signedIn={signedIn} isSignedIn={isSignedIn} />
</Route>
{signedIn && (
<>
<SideMenu />
<Route path="/dashboard" exact component={Dashboard} />
<Route path="/registration-request/seller" component={Seller} />
<Route
path="/registration-request/reseller"
component={Reseller}
/>
<Route path="/registration-request/sales" component={Sales} />
<Route path="/users" component={Users} />
<Route path="/sellers" component={Sellers} />
<Route path="/character-upload" component={Character_Upload} />
<Route path="/campaign-design" component={Campaign_Design} />
<Route path="/levels-design" component={Levels_Design} />
<Route path="/sellingcoins" component={SellingCoins} />
</>
)}
</Switch>
</div>
</>
);
}
export default App;
The signedIn state only lives in memory, and the initial value is false. When you reload the page, you reload the app, which remounts/reinitializes the components.
The solution is typically to persist your app state to local storage, and initialize from localStorage.
Using a state lazy initializer function you can read the localStorage for the saved state and set the initial state.
const [signedIn, isSignedIn] = useState(() => {
return !!JSON.parse(localStorage.getItem("signedIn"));
});
Use an useEffect hook to persist state changes to localStorage. When a user signs in and the signedIn state updates, this will trigger the useEffect hook's callback and will save the state value into localStorage.
useEffect(() => {
localStorage.setItem("signedIn", JSON.stringify(signedIn));
}, [signedIn]);
The signedIn flag will be set to false on page refresh. Instead of using it in the state variable use the local Storage/ Session Storage.
you can read more about local storge

React Router - Go back to the last page visited, and not the default component

I am having a bit of an issue with React Router that I can not seem to figure out. It does not go back to the very last page visited, rather the first page it loaded. Here is an example.
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import PrivateRoute from './utils/auth/PrivateRoute';
<Router>
<PrivateRoute exact path="/dashboard" component={DashboardView} />
<PrivateRoute exact path="/games" component={Games} />
<PrivateRoute
exact
path="/viewgame/:id*/"
component={SingleGameView}
/>
</Router>
When you go to /dashboard, you can click to view a games list that takes you to /games. You can then click on a game to see a single view of it, which takes you to /viewgame/:id*
Like so: /dashboard -> /games -> /viewgame/:id*
When you click on a game and are taken to /viewgame/, and then decide to click back in the browser, it takes me back to /dashboard instead of taking me back to /games. It is skipping over the last visited page, and taking me back to the first loaded page. I can send someone back to a route by setting up my own 'click to go back' button, but I need the browsers actual back and forward button to do this.
PrivateRoute is a HOC I setup to check to make sure the user accessing the route is authenticated or not. Otherwise they are booted. In case that could be the issue here is that component:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
//Utils - Auth
import { userAuth } from '../../../authentication/authentication';
const { isAuthenticated } = userAuth;
//Checks if a user isAuthenticated. If so, it renders the passed in secure component. If not, it renders a redirect to /signin
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/signin',
state: { from: props.location }
}}
/>
)
}
/>
);
export default PrivateRoute;
Here’s a snapshot of the PrivateRoute props when it’s rendered a component:
You can achieve this by calling goBack() function in history object inside withRouter().
import React from 'react';
import { withRouter } from 'react-router-dom'
export default withRouter(({ history }) => {
return (
<div>
<button onClick={() => history.goBack()}>BACK</button>
</div>
)
});
You can simply use the useHistory hook from react-router-dom
import { useHistory } from "react-router-dom";
const history = useHistory();
...
<div onClick={ ()=>history.goBack() }>Back </div>
Remove 'exact' from your routes props.

Integrating react-cookie with react redux

My main application is based on this old boilerplate which I have been slowly updating. Currently, all of the dependencies have been updated except for react-cookie.
I am trying to upgrade react-cookie to version 3.0.4 using this tutorial but I need some help overcoming some challenges I am facing during the transition process.
Following the tutorial, I changed index.js to
ReactDOM.render(
<CookiesProvider>
<Provider store={store}>
<App />
</Provider>
</CookiesProvider>,
document.querySelector('.wrapper'));
Now, my app.js file looks like this:
import React, { Component } from 'react'
import { withCookies } from 'react-cookie'
import Routes from '../Routes'
class App extends Component {
render() {
return (
<div className="container">
<Routes cookies={this.props.cookies} />
</div>
);
}
}
export default withCookies(App)
Now, my biggest concern comes here. My Routes component was never meant to be a Redux container so I changed it to this to accommodate the tutorial:
import React from 'react'
import { connect } from 'react-redux'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import ScrollUpButton from 'react-scroll-up-button'
// Import miscellaneous routes and other requirements
import NotFoundPage from './components/pages/not-found-page'
// Import Header and footer
import HeaderTemplate from './components/template/header'
import FooterTemplate from './components/template/footer'
// Import static pages
import HomePage from './components/pages/home-page'
// Import authentication related pages
import Register from './components/auth/register'
import Login from './components/auth/login'
import Logout from './components/auth/logout'
import ForgotPassword from './components/auth/forgot_password'
import ResetPassword from './components/auth/reset_password'
import ConfirmationMessage from './components/auth/confirmation_message'
import ResendVerificationEmail from './components/auth/resend_verification_email'
// Import dashboard pages
import Dashboard from './components/dashboard/dashboard'
import ChangePassword from './components/dashboard/profile/change-password'
// Import simulator pages
import Simulator from './components/simulator/index'
// Import higher order components
import RequireAuth from './components/auth/require_auth'
const BrowserRoutes = () => (
<BrowserRouter>
<div>
<HeaderTemplate logo="Stress Path Simulator" />
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<Route exact path="/logout" component={Logout} />
<Route exact path="/forgot-password" component={ForgotPassword} />
<Route exact path="/reset-password/:resetToken" component={ResetPassword} />
<Route exact path="/confirmation-message" render={() => <ConfirmationMessage message="Please click on the link we sent to your email to verify your account." /> } />
<Route exact path="/resend-verification-email" component={ResendVerificationEmail} />
<Route exact path="/profile/change-password" component={RequireAuth(ChangePassword)} />
<Route exact path="/confirmation-password-changed" render={() => RequireAuth(<ConfirmationMessage message="Password has been successfully changed!" />)} />
<Route exact path="/simulator" component={RequireAuth(Simulator)} />
<Route exact path="/dashboard" component={RequireAuth(Dashboard)} />
<Route component={NotFoundPage} />
</Switch>
<FooterTemplate />
<ScrollUpButton />
</div>
</BrowserRouter>
);
const mapStateToProps = (state, ownProps) => {
return ({
state: state,
cookies: ownProps.cookies
});
}
export const Routes = connect(mapStateToProps, null)(BrowserRoutes)
export default Routes
I believe the problem essentially arises here. By doing so, I thought I would have been able to use the cookies from every single component like this:
//get this.props.cookies
const { cookies } = this.props;
//setting a cookie
cookies.set('name', 'Ross', { path: '/' });
//getting a cookie
cookies.get('name');
However, that doesn't seem the case and I cannot get cookies to work in any of my components especially in my actions/auth.js.
Does anyone have any suggestions? How can I efficiently use cookies in this scenario? I am assuming I can send down the cookies prop to each component that needs it but I am curious to find out what could be the best/cleanest way of using react-cookie with redux. I am fairly new to the MERN JavaScript software stack and mostly self-thought so I am a bit confused about some concepts. For example, if in Routes I am saving cookies into the redux's store, how can I access those cookies afterwards?
Instead of passing the cookies from the App/Router down, it is better to wrap only the components that will need the cookies. For example your Login component would look like this:
class Login extends React.Component {
render() {
let { cookies } = this.props;
let useCookie = cookies.get("testCookie");
...
}
}
export default withCookies(connect(mapStateToProps, null)(Login));

Categories

Resources