Nested Router in ReactJS - Show blank page on refresh - javascript

I am a beginner in ReactJS and React Router and I am having some issues with my nested router.
For my main router in App.js, things work well. So I can visit my landing page (/), login page (/login), and register page (/register). And once I reach this page, if I do a manual refresh on my Chrome Browser (ctrl r), the page refresh and render accordingly.
Below is my App.js
import React from "react";
import { Router, Switch } from "react-router-dom";
import Login from "./components/Login";
import Register from "./components/Register";
import Dashboard from "./components/Dashboard";
import DynamicLayout from './router/DynamicLayout';
import LandingPage from './components/homepage/LandingPage';
import { history } from "./helpers/history";
const App = () => {
return (
<Router history={history}>
<div className="App">
<Switch>
<DynamicLayout
exact
path="/"
component={LandingPage}
layout="LANDING_NAV"
/>
<DynamicLayout
exact
path="/login"
component={Login}
layout="LOGIN_PAGE"
/>
<DynamicLayout
exact
path="/register"
component={Register}
layout="REGISTER_PAGE"
/>
<DynamicLayout
path="/dashboard"
component={Dashboard}
layout="DASHBOARD_PAGE"
/>
</Switch>
</div>
</Router>
);
};
export default App;
Below is my DynamicLayout.js
import React from "react";
import { BrowserRouter as Route, Switch } from "react-router-dom";
import Login from "../components/Login";
import Register from "../components/Register";
const DynamicLayout = (props) => {
const { component: RoutedComponent, layout, ...rest } = props;
const actualRouteComponent = <RoutedComponent {...props} />;
switch (layout) {
case "LANDING_NAV": {
return <div>{actualRouteComponent}</div>;
}
case "LOGIN_PAGE": {
return <div>{actualRouteComponent}</div>;
}
case "REGISTER_PAGE": {
return <div>{actualRouteComponent}</div>;
}
case "DASHBOARD_PAGE": {
return <div>{actualRouteComponent}</div>;
}
default: {
return (
<div>
<h2>Default Nav</h2>
{actualRouteComponent}
</div>
);
}
}
};
export default DynamicLayout;
The issue is with my nested router which is in my Dashboard component. Basically, once a admin user logged in, they will be shown the admin dashboard.
Below is my Dashboard component.
import React, { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { history } from "../helpers/history";
import { useHistory } from 'react-router-dom';
import {
BrowserRouter as Router,
Route,
Switch,
} from "react-router-dom";
import { logout } from "../actions/auth";
import AdminSideNavBar from "../components/admin/AdminSideNavBar";
import AdminManageUsers from "./admin/AdminManageUsers";
import AdminPendingApprovalUsers from "../components/admin/AdminPendingApprovalUsers";
import AdminDeactivatedUsers from "./admin/AdminDeactivatedUsers";
import AdminRegisterInternalUsers from "./admin/AdminRegisterInternalUsers";
import AdminLogs from "../components/admin/AdminLogs";
import BrokerSideNavBar from "../components/broker/BrokerSideNavBar";
import ShareholderSideNavBar from "../components/shareholder/ShareholderSideNavBar";
import Login from "../components/Login"
import AdminActivatedUsers from "./admin/AdminActivatedUsers";
const Dashboard = () => {
const [showAdminDashboard, setShowAdminDashboard] = useState(false);
const [showBrokerDashboard, setShowBrokerDashboard] = useState(false);
const [showShareholderDashboard, setShowShareholderDashboard] =
useState(false);
const { user: currentUser } = useSelector((state) => state.auth);
const dispatch = useDispatch();
useEffect(() => {
if (currentUser) {
setShowAdminDashboard(currentUser.roles.includes("ROLE_ADMIN"));
setShowBrokerDashboard(currentUser.roles.includes("ROLE_BROKER"));
setShowShareholderDashboard(
currentUser.roles.includes("ROLE_SHAREHOLDER")
);
}
}, [currentUser]);
const logOut = () => {
dispatch(logout());
};
let history = useHistory();
return (
<div>
{showAdminDashboard && (
<Router history= {history}>
<div className="wrapper">
<AdminSideNavBar />
<Switch>
<Route exact path="/dashboard" component={AdminPendingApprovalUsers} />
<Route exact path="/logs" component={AdminLogs} />
<Route exact path="/manageusers" component={AdminManageUsers} />
<Route exact path="/activeusers" component={AdminActivatedUsers} />
<Route exact path="/deactivatedusers" component={AdminDeactivatedUsers} />
<Route exact path="/registerinternalusers" component={AdminRegisterInternalUsers} />
</Switch>
</div>
</Router>
)}
{showBrokerDashboard && <BrokerSideNavBar />}
{showShareholderDashboard && <ShareholderSideNavBar />}
</div>
);
};
export default Dashboard;
With my side nav bar (AdminSideNavbar component), I can navigate to the various pages. Like /logs, /manageusers, /activeusers etc.
Below is my AdminSideNavBar component
import React from "react";
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { logout } from "../../actions/auth";
import {
CDBSidebar,
CDBSidebarContent,
CDBSidebarFooter,
CDBSidebarHeader,
CDBSidebarMenu,
CDBSidebarMenuItem,
} from "cdbreact";
import { NavLink } from "react-router-dom";
const AdminSideNavBar = () => {
const { user: currentUser } = useSelector((state) => state.auth);
const dispatch = useDispatch();
const { isLoggedIn } = useSelector((state) => state.auth);
const logOut = () => {
dispatch(logout());
};
return (
<div className="stickysidenav">
<CDBSidebar textColor="#fff" backgroundColor="#333">
<CDBSidebarHeader prefix={<i className="fa fa-bars fa-large"></i>}>
<a
href="/"
className="text-decoration-none"
style={{ color: "inherit" }}
>
TradeDuh
</a>
<p>{currentUser.username}</p>
{/* {isLoggedIn && (
<div className="wrapper">
<p>{currentUser.username}</p>
</div>
)} */}
</CDBSidebarHeader>
<CDBSidebarContent className="sidebar-content">
<CDBSidebarMenu>
<NavLink exact to="/dashboard" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="columns">Dashboard</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/logs" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="table">Logs</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/uploadcompany" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="edit">Update Nasdaq Stocks</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/manageusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="users-cog">Manage Users</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/activeusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="user-check">Active Users</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/deactivatedusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="user-times">De-activated Users</CDBSidebarMenuItem>
</NavLink>
<NavLink to="/registerinternalusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="user-plus">
Add Internal Users
</CDBSidebarMenuItem>
</NavLink>
<NavLink
exact
to="/login"
activeClassName="activeClicked"
onClick={logOut}
>
<CDBSidebarMenuItem icon="sign-out-alt">
Log Out
</CDBSidebarMenuItem>
</NavLink>
</CDBSidebarMenu>
</CDBSidebarContent>
<CDBSidebarFooter style={{ textAlign: "center" }}>
<div
style={{
padding: "20px 5px",
}}
>
TradeDuh (FDM - S21-Java-02)
</div>
</CDBSidebarFooter>
</CDBSidebar>
</div>
);
};
export default AdminSideNavBar;
The issue is, once I reach the various page, if I do a manual refresh (ctrl r), my whole screen will turn white/blank.
So say if I click on /logs, AdminLogs component is rendered, which is all good. BUT... if I now press ctrl r to do a manual fresh, the AdminLogs component don't show anymore. All I see is a blank white screen.
This is totally different from what is happening in my main router where I can do a manual page fresh and the page will render accordingly.
Any idea on how to solve this? What is my issue here?
Thank you for the help!

Related

React app display blank page without any compilation error

I am not sure what went wrong with my react app below, it compile successfully without error but doesn't show anything (just show a blank page). Can anyone point out what went wrong with my code? Sorry I am new to react.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css'
import { BrowserRouter } from 'react-router-dom'
import App from './App';
ReactDOM.render((
// <Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
// </Provider>
), document.getElementById('root'))
App.js
import { BrowserRouter as Router, Route, Link, NavLink } from "react-router-dom";
import Home from "./components/Home";
import NewBuilding from "./components/NewBuilding";
import React, { Component } from "react";
import Web3 from 'web3';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import "./App.css";
import { useEffect, useState } from 'react';
function App() {
const [currentAccount, setCurrentAccount] = useState(null);
const checkWalletIsConnected = async () => {
const { ethereum } = window;
if (!ethereum) {
console.log("Make sure you have Metamask installed!");
return;
} else {
console.log("Wallet exists! We're ready to go!")
}
const accounts = await ethereum.request({ method: 'eth_accounts' });
if (accounts.length !== 0) {
const account = accounts[0];
console.log("Found an authorized account: ", account);
setCurrentAccount(account);
} else {
console.log("No authorized account found");
}
}
const connectWalletHandler = async () => {
const { ethereum } = window;
if (!ethereum) {
alert("Please install Metamask!");
}
try {
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
console.log("Found an account! Address: ", accounts[0]);
setCurrentAccount(accounts[0]);
} catch (err) {
console.log(err)
}
}
const connectWalletButton = () => {
return (
<button onClick={connectWalletHandler} className='cta-button connect-wallet-button'>
Connect Wallet
</button>
)
}
useEffect(() => {
checkWalletIsConnected();
}, [])
return (
<div>
<Router>
<AppBar position="static" color="default" style={{ margin: 0 }}>
<Toolbar>
<Typography variant="h6" color="inherit">
<NavLink className="nav-link" to="/">Home</NavLink>
</Typography>
<NavLink className="nav-link" to="/new/">New</NavLink>
</Toolbar>
</AppBar>
<Route path="/" exact component={Home} />
<Route path="/new/" component={NewBuilding} />
</Router>
</div>
)
}
export default App;
My Home.js is residing in a components folder
The folder structure is as below
Home.js
import React, { useState, useEffect } from "react";
import { makeStyles } from '#material-ui/core/styles';
import Web3 from 'web3'
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1),
},
input: {
display: 'none',
},
}));
const Home = () => {
const classes = useStyles();
const [ contract, setContract] = useState(null)
const [ accounts, setAccounts ] = useState(null)
const [ funds, setFunds ] = useState([])
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))
useEffect(() => {
}, []);
return (
<div><h2>Home</h2></div>
)
}
export default Home;
Your Route component should have the prop element instead of component, see the migration guide.
<Route path="/" exact element={<Home />} />
In App.js you're wrapping your components again in a Router. Instead you should wrap your Route components in a Routes.
import { Routes, Route, Link, NavLink } from "react-router-dom";
...
<div>
<AppBar position="static" color="default" style={{ margin: 0 }}>
<Toolbar>
<Typography variant="h6" color="inherit">
<NavLink className="nav-link" to="/">
Home
</NavLink>
</Typography>
<NavLink className="nav-link" to="/new/">
New
</NavLink>
</Toolbar>
</AppBar>
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/new/" element={<NewBuilding />} />
</Routes>
</div>

Why will <Link> work in header but not on home page using React-Router-Dom? [duplicate]

This question already has an answer here:
Difference in the navigation (React Router v6)
(1 answer)
Closed last month.
I am creating a website that is using React Router. All my links are working fine in the header but when I try to create a link on my home page it will not work. There must be a step I'm missing. Any help would be appreciated!
App:
import React, { useEffect } from "react";
import { useState } from 'react';
import { BrowserRouter, Routes, Route, Link } from "react-router-dom"
import Header from './Header';
import MilesForm from "./MilesForm";
import Weather from './Weather';
import PaceCalculator from "./PaceCalculator";
import WeeklyGoal from "./WeeklyGoal";
import Home from "./Home";
const getGoal = JSON.parse(localStorage.getItem('goal') || "[]");
const App = () => {
const [goal, setGoal] = useState(getGoal);
const [milesToGo, setMilesToGo] = useState();
const handleChange = (e) => {
setGoal(e.target.value)
}
const handleSubmit = (e) => {
e.preventDefault();
setMilesToGo(goal)
localStorage.setItem('goal', goal)
window.location.reload();
}
return (
<BrowserRouter>
<div>
<Header />
<Routes>
{/* <Route path="/" element={<Home />} /> */}
<Route path="Home" element={<Home />} />
<Route path="WeeklyGoal" element={[
<WeeklyGoal
handleChange={handleChange}
handleSubmit={handleSubmit}
goal={goal}
/>,
<MilesForm
goal={goal}
milesToGo={milesToGo}
setMilesToGo={setMilesToGo}
path="./MilesForm"
/>
]} />
<Route path="Weather" element={<Weather />} />
<Route path="Pace" element={<PaceCalculator />} />
</Routes>
</div>
</BrowserRouter>
);
};
export default App;
Header:
import React from "react";
import './css/header.css';
import { Link } from 'react-router-dom';
import { useState } from 'react';
const Header = () => {
const [burger, setBurger] = useState(true)
const handleToggle = () => {
{ burger ? setBurger(false) : setBurger(true) }
}
return (
<div className="header-style">
<h1 className="header-title">3-2run</h1>
<button className="burger-btn" onClick={handleToggle}>
<p></p>
<p></p>
<p></p>
</button>
<div
className={burger === false
? "menu-container"
: "hide-menu-container"
}
>
<ul>
<li><Link to="Home">Home</Link></li>
<li><Link to="WeeklyGoal">Track your miles</Link></li>
<li><Link to="Weather">Weather</Link></li>
<li><Link to="Pace">Pace Calculator</Link></li>
</ul>
</div>
</div>
)
}
export default Header;
Home: Here I have a link to the weather page that is not working. I'm confused as to why this same link will work on the header page but not on this one.
import React from 'react';
import './css/home.css';
import { Link } from 'react-router-dom'
const Home = () => {
return (
<div className='home-container'>
<div className='track-miles-link'>
<h2>Track Your Miles</h2>
</div>
<div className='get-weather'>
<Link to="Weather"><h2>Check Weather</h2></Link>
</div>
<div className='get-pace'>
<h2>Pace Calculator</h2>
</div>
</div>
)
}
export default Home;
You don't have a route with the path /Home/Weather so
<Link to="Weather"><h2>Check Weather</h2></Link>
won't work
You have /Weather route so
<Link to="/Weather"><h2>Check Weather</h2></Link>
or
<Link to="../Weather"><h2>Check Weather</h2></Link>
will work

Reactjs - Issue Sending Dispatch to Reducer?

I am working on putting together a webpage with routing and I am having trouble getting redux to work. My goal is to send a GET response to the reducer but just to test the setup right now my goal is to send true. I can retrieve data from the redux store but I can't seem to send it and I am unsure where I might be going wrong. Here is what is supposed to happen:
Auth is checked in login or signup
App.js is wrapped in a provider
User can go to Cart.js and by clicking a button dispatch the value true
The can navigate to Menu.js and should be able to console.log the new value from the reducer
My problem: I can't seem to actually dispatch the true value. Nothing breaks but when I go to the Menu page, the console log shows the initial state of the reducer.
This has worked for me before in React Native. I'm wondering if I should be setting this up differently? or if authentication is messing things up?
Below is a sample of my code:
App.js
import React, { Component } from 'react';
import {
Route,
BrowserRouter as Router,
Switch,
Redirect,
} from "react-router-dom";
import Home from './pages/Home';
import Signup from './pages/Signup';
import Login from './pages/Login';
import Menus from './pages/Menus';
import Carts from './pages/Carts';
import Orders from './pages/Orders';
import Land from './pages/Land';
import { auth } from './services/firebase';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import ourReducer from './store/reducer';
const store = createStore(ourReducer);
global.api = 'https://pitapal.metis-data.site'
//global.api = 'http://localhost:3008';
function PrivateRoute({ component: Component, authenticated, ...rest }) {
return (
<Route
{...rest}
render={(props) => authenticated === true
? <Component {...props} />
: <Redirect to={{ pathname: '/login', state: { from: props.location } }} />}
/>
)
}
function PublicRoute({ component: Component, authenticated, ...rest }) {
return (
<Route
{...rest}
render={(props) => authenticated === false
? <Component {...props} />
: <Redirect to='/home' />}
/>
)
}
class App extends Component {
constructor() {
super();
this.state = {
authenticated: false,
loading: true,
};
}
componentDidMount() {
auth().onAuthStateChanged((user) => {
if (user) {
this.setState({
authenticated: true,
loading: false,
});
} else {
this.setState({
authenticated: false,
loading: false,
});
}
})
}
render() {
return this.state.loading === true ? <h2>Loading...</h2> : (
<Provider store={ store }>
<Router>
<Switch>
<Route exact path="/" component={Signup}></Route>
<PrivateRoute path="/home" authenticated={this.state.authenticated} component={Home}></PrivateRoute>
<PrivateRoute path="/menus" authenticated={this.state.authenticated} component={Menus}></PrivateRoute>
<PrivateRoute path="/carts" authenticated={this.state.authenticated} component={Carts}></PrivateRoute>
<PrivateRoute path="/order" authenticated={this.state.authenticated} component={Orders}></PrivateRoute>
<PublicRoute path="/signup" authenticated={this.state.authenticated} component={Signup}></PublicRoute>
<PublicRoute path="/login" authenticated={this.state.authenticated} component={Login}></PublicRoute>
</Switch>
</Router>
</Provider>
);
}
}
export default App;
Reducer.js
import { combineReducers } from 'redux';
const INITIAL_STATE = {
carts: 'nothing'
};
const ourReducer = (state = INITIAL_STATE, action) => {
const newState = { ...state };
switch (action.type) {
case "CARTS":
return {
...state,
carts: action.value
}
break;
}
return newState;
};
export default combineReducers({
reducer: ourReducer,
});
Carts.js
class Carts extends Component {
render() {
return (
<Container>
<Button onClick={()=>this.props.setCart(true)}>sendToRedux</Button>
</Container>
);
}
}
const mapStateToProps = (state) => {
const { reducer } = state
return { reducer }
};
const mapDispachToProps = dispatch => {
return {
setCart: (y) => dispatch({ type: "CARTS", value: y })
};
}
export default connect(mapStateToProps,
mapDispachToProps
)(Carts);
Menu.js
import React, { Component } from 'react';
import Header from "../components/Header";
import MenuItem from '../components/MenuItem';
import classes from './menus.module.css'
import { auth, db } from "../services/firebase";
import { Container, Col, Row } from 'react-bootstrap';
import { connect } from 'react-redux';
class Menu extends Component {
render() {
console.log('my carts data:', this.props.reducer.carts);
}
return (
<Container>
welcome to menu
</Container>
);
}
}
const mapStateToProps = (state) => {
const { reducer } = state
return { reducer }
};
export default connect(mapStateToProps)(Menu);
EDIT:
here is my screenshot from Redux Devtools, this means the dispatch is definitely being sent correct?
So it seems the issue is that when I navigate a page using my header component, state gets reloaded, the entire app is relaoded. Wondering if someone knows what it might be. Below is my header component:
Header.js
import { Link } from 'react-router-dom';
import { auth } from '../services/firebase';
//import "./header.css";
import React, { Component } from 'react'
import { Navbar, Nav, NavItem, NavDropdown, Form, FormControl, Button } from 'react-bootstrap'
// import {Link} from 'react-router-dom'
//import classes from './navbar.module.css';
import 'bootstrap/dist/css/bootstrap.min.css';
class Header extends Component {
render() {
return (
<div>
{auth().currentUser
?
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="/login">Home</Nav.Link>
<Nav.Link href="/menus">Manage my Menus</Nav.Link>
</Nav>
<Nav>
<Button onClick={() => auth().signOut()} variant="outline-success">Sign Out</Button>
</Nav>
</Navbar.Collapse>
</Navbar>
:
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="/login">Login</Nav.Link>
<Nav.Link href="/signup">Sign Up</Nav.Link>
</Nav>
<Nav>
<Nav.Link href="contact">Contact Us</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
}
</div>
)
}
}
export default Header;
Issue
Your Header is using plain anchor tags to issue navigation to your route pages which has the side-effect of also doing a page load.
Solution
Use the react-router-dom Link component for linking.
Either specify the as prop of the Nav.Link or use Link
<Nav.Link as={Link} to="/login">Home</Nav.Link>
or
<Link to="/login">Home</Link>
class Header extends Component {
render() {
return (
<div>
{auth().currentUser
?
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Link to="/login">Home</Link>
<Link to="/menus">Manage my Menus</Link>
</Nav>
<Nav>
<Button onClick={() => auth().signOut()} variant="outline-success">Sign Out</Button>
</Nav>
</Navbar.Collapse>
</Navbar>
:
<Navbar className="fixed-top" collapseOnSelect expand="lg" style={{ backgroundColor: '#485671' }} variant="dark">
<Navbar.Brand href="#home">PitaPal</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Link to="/login">Login</Link>
<Link to="/signup">Sign Up</Link>
</Nav>
<Nav>
<Link to="contact">Contact Us</Link>
</Nav>
</Navbar.Collapse>
</Navbar>
}
</div>
)
}
}

React Mulitple rendering functional component

hy i begin in react and i try to get user data from my api with my cookie, i have the data but when i console.log() the user data i have 4 undefined and then 2 same object data. The problem is i don't know why and when i try to get user.id in an other components using props i have tpyerror id undefined.
import React, {useState, useEffect} from "react";
import NavBar from "./component/NavBar";
import Navigation from "./component/Navigation"
import Cookie from "js-cookie"
import axios from "axios"
import "./App.css";
function App() {
const [user, setUser] = useState()
const [logged, setLogged] = useState(false)
const cookie = Cookie.get("login")
useEffect(() => {
axios.post('/getdatafromcookie', cookie)
.then((res) => {
if(res.data.success === true){
setLogged(true)
setUser(res.data.user)
}
})
}, [])
console.log(user)
return (
<div className="App">
<header className="NavHeader">
<NavBar user={user} logged={logged} />
</header>
<Navigation user={user} logged={logged}/>
</div>
);
}
export default App;
And the console log shows me :
Undefined
Undefined
Undefined
Undefined
{id: "31", email:"test#test.fr" etc.....}
{id: "31", email:"test#test.fr" etc.....}
Navbar
import React, { useState, useEffect } from "react";
import RegisterForm from "../component/RegisterForm";
import RegisterLogin from "../component/RegisterLogin";
import { Navbar, Nav, Dropdown } from "react-bootstrap";
import { Button } from "#material-ui/core"
export default function NavBar(props) {
const [modalLoginShow, setModalLoginShow] = useState();
const [modalRegisterShow, setModalRegisterShow] = useState();
const user = props.user
const islogged = props.logged
if(islogged === false)
{
return (
<Navbar collapseOnSelect expand="lg" bg="transparent" variant="light">
<Navbar.Brand href="/">Matchandate</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto"></Nav>
<Nav>
<Nav.Link onClick={() => setModalLoginShow(true)}>
<Button variant="contained" color="secondary">Login</Button>
</Nav.Link>
<Nav.Link onClick={() => setModalRegisterShow(true)}>
<Button variant="contained" color="secondary" >Register</Button>
</Nav.Link>
</Nav>
</Navbar.Collapse>
<RegisterLogin show={modalLoginShow} onHide={() => setModalLoginShow(false)} />
<RegisterForm show={modalRegisterShow} onHide={() => setModalRegisterShow(false)} />
</Navbar>
)
}
return(
<Navbar collapseOnSelect expand="lg" bg="transparent" variant="light">
<Navbar.Brand href="/">Matchandate</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto"></Nav>
<Nav>
<Nav.Link href="/profile">
<Button variant="contained" color="primary">Profile</Button>
</Nav.Link>
<Nav.Link href="/logout">
<Button variant="contained" color="primary" >Logout</Button>
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
)
}
Navigation
import React from "react"
import Slider from "./SliderHome";
import Activate from "./Activate";
import ForgotPwd from "./Pages/ForgotPwd"
import ChangePwd from "./Pages/ChangePwd"
import UserProfile from "./Pages/UserProfil";
import ErrorPage from "./Pages/ErrorPage"
import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom";
export default function Navigation(props){
const user = props.user
const islogged = props.logged
if(islogged){
return(
<Router>
<Switch>
<Route exact path="/" exact component={Slider} />
<Route exact path="/profile" component={() => <UserProfile user={user} />} />
{/* <Route path="/user/:id" component={ChangePwd}/> */}
<Route path="/" component={ErrorPage} />
</Switch>
</Router>
)
}
return (
<Router>
<Switch>
<Route exact path="/" exact component={Slider} />
<Route path="/activate" component={Activate} />
<Route path="/forgot-pwd" component={ForgotPwd}/>
<Route path="/changepwd" component={ChangePwd}/>
{/* <Route path="/user/:id" component={ChangePwd}/> */}
<Route path="/" component={ErrorPage} />
</Switch>
</Router>
)
}
The problem is i don't know why and when i try to get user.id in an other components using props i have tpyerror id undefined.
The reason for that is that you try to get the id of the user before the user is loaded, which means you're doing something like null.id which is undefined (depends on what useState returns when called without any arguments, probably null)
The reason you get multiple Undefined in console.log is:
the first time your App component is rendered, useEffect didn't finish calling the api yet, so user is still undefined, the 2nd time is because you called setLogged(true) so user is still undefined, the 3rd and 4th times ... i'm not sure, but you're probably changing the state somehow which causes a re-render
the proper wait to fix this, would be to wait until user is defined (ie the api call is finished), you can do that by using a simple if statement, something like
if (user.id) {
// return components when the user is logged in
} else {
// return components where the user is not logged in, usually a "loading" screen
}
Now you said user.id returns type error but i couldn't find any user.id in your code, so i assumed that you didn't post the whole thing.
This happens because useEffect is executed after the first render, so, the first time user is null, you will need to guard your code to render once you have data inside user
return user ? <div className=“app”><NavBar user={user}/></div> : <div>loading</div>)
The logs being printed so many times is because strict mode in development
In yours first render: your user is undefined it's normal because your are not defined a default value in your usestate you can change your code by this const [user, setUser] = useState({}) or this
import React, {useState, useEffect} from "react";
import NavBar from "./component/NavBar";
import Navigation from "./component/Navigation"
import Cookie from "js-cookie"
import axios from "axios"
import "./App.css";
function App() {
const [user, setUser] = useState()
const [logged, setLogged] = useState(false)
const cookie = Cookie.get("login")
useEffect(() => {
axios.post('/getdatafromcookie', cookie)
.then((res) => {
if(res.data.success === true){
setLogged(true)
setUser(res.data.user)
}
})
}, [])
console.log(user)
return (
<div className="App">
<header className="NavHeader">
{user ? <NavBar user={user} logged={logged} /> : "loading"}
</header>
{user ? <Navigation user={user} logged={logged}: "loading" />
</div>
);
}
export default App;

React hook Redirect on component mount

I am trying to manage session after successful login while redirecting to some page on form submit.
I would do this usually, in a class component:
componentDidMount() {
if (context.token) {
return <Redirect to="/" />
}
}
But I want to use React hooks, therefore; the following code is not redirecting anywhere:
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Switch, Route, Redirect, Link } from "react-router-dom";
es6
const HomePage = props => (
<div>
<h1>Home</h1>
</div>
);
const AboutUsPage = props => {
useEffect(() => {
redirectTo();
}, []);
return (
<div>
<h1>About us</h1>
</div>
);
};
function redirectTo() {
return <Redirect to="/" />;
}
function App() {
return (
<div className="App">
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/us">About us</Link>
</nav>
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/us" component={AboutUsPage} />
</Switch>
</BrowserRouter>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Working sandbox: https://codesandbox.io/s/blue-river-6dvyv?fontsize=14
I have read that if the hook useEffect() returns a function it will only work when the component unmounts. But it should redirect when the component is being mounted.
Any suggestions? Thanks in advance.
You could set redirect variable on the state and based on it redirect in render:
const AboutUsPage = props => {
const [redirect, setRedirect] = useState(false);
useEffect(() => {
setRedirect(true); // Probably need to set redirect based on some condition
}, []);
if (redirect) return redirectTo();
return (
<div>
<h1>About us</h1>
</div>
);
};
You could have it so that the component selectively renders the page based on whether or not the page is given a token.
const AboutUsPage = ({token}) => (
token ? (
<Redirect to="/" />
) : (
<div>
<h1>About us</h1>
</div>
)
);
However, if you would still like to use context when implementing this with React Hooks you can read up on how to use context with hooks in this article. It shows you how you can incorporate context into React with only a few lines of code.
import React, {createContext, useContext, useReducer} from 'react';
export const StateContext = createContext();
export const StateProvider = ({reducer, initialState, children}) =>(
<StateContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);
Done with hooks and context, your AboutUsPage component would resemble something like this.
import { useStateValue } from './state';
const AboutUsPage = () => {
const [{token}, dispatch] = useStateValue();
return token ? (
<Redirect to="/" />
) : (
<div>
<h1>About us</h1>
</div>
);
};
import {Redirect, Switch} from "react-router-dom";
and inside Switch....
<Switch>
<Redirect exact from="/" to="/home" />
</Switch>
This solved my issue.

Categories