React Router V4 is updating URL, but not refreshing page - javascript

I create simple app and i try use in it react-router but i have problem.
When user click register or login the page should render necessary form but now to page change user must refresh page and then page change component i dont know why.
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'))
App class:
class App extends React.Component {
render() {
return (
<div className="App">
<Navbar/>
</div>
);
}
}
Navbar class:
class Navbar extends React.Component {
render(){
return (
<Nav bsStyle="tabs">
<LinkContainer to="/login" >
<NavItem >
LogIn
</NavItem>
</LinkContainer>
<LinkContainer to="/Register" >
<NavItem >
Register
</NavItem>
</LinkContainer>
<Router>
<BrowserRouter>
<Switch>
<Route path="/Register" component={Register} />
<Route path="/Login" component={Login} />
</Switch>
</BrowserRouter>
</Router>
</Nav>
)
}}

You will have to have your BrowserRouter as a top level component. The nav is the place which triggers what component has to be rendered.
ReactDOM.render(<App />, document.getElementById('root'));
App.js
class App extends React.Component {
render() {
return (
<div className="App">
<Navbar/>
<Router>
<BrowserRouter>
<Switch>
<Route path="/Register" component={Register} />
<Route path="/Login" component={Login} />
</Switch>
</BrowserRouter>
</Router>
</div>
);
}
}
Nav.js
class Navbar extends React.Component {
render(){
return (
<Nav bsStyle="tabs">
<LinkContainer to="/login" >
<NavItem >
LogIn
</NavItem>
</LinkContainer>
<LinkContainer to="/Register" >
<NavItem >
Register
</NavItem>
</LinkContainer>
</Nav>
)
}}

You have your Routing inside the Navbar component, that won't work.
Change your index.js to look like this:
ReactDOM.render((
<BrowserRouter>
<Switch>
<Route path="/Register" component={Register} />
<Route path="/Login" component={Login} />
<Route path="/" component={App} />
</Switch>
</BrowserRouter>
), document.getElementById('root'))
That should work, let me know if any issues. Also delete the BrowserRouter elements and children from Navbar

use BrowserRouter inside Router
<Router>
<BrowserRouter>
<Switch>
...
</Switch>
</BrowserRouter>
</Router>

Related

React routers not working - It displays a blank page

Here is my App.js from my current project , I am facing an issue, whenever I render all my components individually which are mentioned in the commented part it gives me complete output, but as soon as I render it through the react-router-dom the page turns blank. Please help me with this.
import Topbar from "./components/topbar/Topbar";
import Homepage from "./pages/homepage/Homepage";
import Login from "./pages/login/Login";
import Register from "./pages/register/Register";
import Settings from "./pages/settings/Settings";
import Single from "./pages/single/Single";
import Write from "./pages/write/Write";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Header from "./components/header/Header";
import Posts from "./components/posts/Posts";
function App() {
const currentUser = true;
return (
// <>
// <Topbar/>
// <Header/>
// <Single/>
// <Homepage/>
// <Posts/>
// <Register/>
// <Login/>
// <Settings/>
// </>
<BrowserRouter>
<Topbar />
<Routes>
<Route exact path="/">
<Homepage />
</Route>
<Route path="/posts">
<Homepage />
</Route>
<Route path="/register">
{currentUser ? <Homepage /> : <Register />}
</Route>
<Route path="/login">{currentUser ? <Homepage /> : <Login />}</Route>
<Route path="/post/:id">
<Single />
</Route>
<Route path="/write">{currentUser ? <Write /> : <Login />}</Route>
<Route path="/settings">
{currentUser ? <Settings /> : <Login />}
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;
Try changing your routes to look something like this:
<Route exact path="/" element={<Homepage />} />
The component you want to render should be in the element prop.
https://reactrouter.com/docs/en/v6/getting-started/overview
https://reactrouter.com/docs/en/v6/upgrading/v5
<Route exact path="/" element={<Homepage />} />
The only time you can put something inside a Route as a child element is for nested routing. For example:
<Route path="/teams" element={<Teams />}>
<Route path=":teams" element={<Team />} />
</Route>
I have been through this. I think you should install React Router first (Already installed it seems)
npm install react-router-dom#6
I suggest using it in the following way -
function App() {
return (
<Router>
<div className='container'>
<div className='Header'>
<h2>Blog Site</h2>
</div>
<div className='links'> // Mention your links here
<ul>
<li>
<Link to="/tag">Tags</Link>
</li>
<li>
<Link to="/startup">Startups</Link>
</li>
</ul>
</div>
<Routes> // Describe your routes here
<Route exact path="/tag" element={<Tag />} />
<Route exact path="/startup" element={<Startup />} />
</Routes>
</div>
</Router>
);
}
I have picked small code piece from my project, you can try using my approach.

Error: [Header] is not a <Route> component

I continue to run into the above mentioned error despite my efforts to fix them. The terminal claims the application compiles without issue but nothing shows up on the browser. I found the error my looking at the console. Here is the index.js file for the Header component that the error is referring to:
import React from "react";
import { Route, Navigate, Router } from "react-router-dom";
import Navigation from "../../components/Navigation";
import About from "../../components/About";
import Portfolio from "../../components/Portfolio";
import Contact from '../../components/Contact';
import Resume from '../../components/Resume';
class Header extends React.Component {
render() {
return (
<Router>
<header>
<Navigation />
</header>
<div className="content">
<Route exact path="/" render={() => <Navigate to="/about" replace={true}/>} />
<Route path="/about" component={About} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/contact" component={Contact}/>
<Route path="/resume" component={Resume}/>
</div>
</Router>
);
}
}
export default Header;
Here is the App.js:
import React from 'react';
import Header from './components/Header';
import Footer from './components/Footer';
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Routes } from 'react-router-dom';
function App() {
return (
<div>
<Routes>
<Header />
<Footer />
</Routes>
</div>
);
}
export default App;
I can provide further code if it is needed.
In react-router-dom version 6 Routes components can have only Route or React.Fragment as a child component, and Route components can have only Routes or another Route component as parent. Header is not a Route component and fails the invariant.
Move the Router into app and render the Header and Footer components into it instead, then wrap the Route components in Routes.
App
function App() {
return (
<div>
<Router>
<Header />
<Footer />
</Router>
</div>
);
}
Header
Fix the Route components, they no longer use component or render to render the routed components, instead they now use an element prop to render ReactElements, i.e. JSX.
class Header extends React.Component {
render() {
return (
<div>
<header>
<Navigation />
</header>
<div className="content">
<Routes>
<Route path="/" element={<Navigate to="/about" replace />} />
<Route path="/about" element={<About />} />
<Route path="/portfolio" element={<Portfolio />} />
<Route path="/contact" element={<Contact />}/>
<Route path="/resume" element={<Resume />}/>
</Routes>
</div>
</div>
);
}
}
Though it may make more sense to move the routes into the app as content between the header and footer.
function App() {
return (
<div>
<Router>
<Header />
<div className="content">
<Routes>
<Route path="/" element={<Navigate to="/about" replace />} />
<Route path="/about" element={<About />} />
<Route path="/portfolio" element={<Portfolio />} />
<Route path="/contact" element={<Contact />}/>
<Route path="/resume" element={<Resume />}/>
</Routes>
</div>
<Footer />
</Router>
</div>
);
}

How can i render out the Nav component everywhere except the Login Page?

// MAIN FUNCTION { APP START }
const App = () => {
return (
<Router>
<Nav />
<Switch>
<Route to="/" exact component={Home} />
<Route to="/login" exact component={Login} />
</Switch>
</Router>
);
};
export default App;
I just want that the Nav component renders everywhere except the login page ??
You can put it inside a route component along with the Home.
<Router> <Switch>
<Route path="/" exact>
<Nav />
<Home />
</Route>
<Route to="/login" exact component={Login} />
</Switch> </Router>

How to switch components using navigation in React?

I am developing a landing page using React. It should have the same navigation bar for all sections and change only its active state.
In App.js file I have used BrowserRouter that routes to Navigation component. My problem is that that Navigation does not work properly, it does not switch components, it switches only pathname. For example when I press Cabinet, it should switch from Home to Cabinet component. Should I use another router for Navigation or not? What would be the best solution for this?
I have tried to create NavRouter component, where I have placed routers for Navigation.
App.js file:
<BrowserRouter>
<Switch>
<Route path='/' exact component={ Navigation }></Route>
<Route path='/cabinet' component={ Navigation }></Route>
<Route path='/catalog' component={ Navigation }></Route>
<Route path='/company' component={ Navigation }></Route>
<Route path='/contacts' component={ Navigation }></Route>
</Switch>
</BrowserRouter>
Navigation file:
class Navigation extends Component {
render() {
const { classes, location: {pathname}, children } = this.props;
return (
<div>
<MuiThemeProvider theme={color}>
<Fragment>
<nav id="menu">
<ul className="navigation">
<li>
<MenuItem component={Link} to='/' selected={'/' === pathname} className="active menuItem" className={classes.menuItemColor}>
Главная
</MenuItem>
</li>
<li>
<MenuItem component={Link} to='/cabinet' selected={'/cabinet' === pathname} className="menuItem" className={classes.menuItemColor}>
Кабинет
</MenuItem>
</li>
<li>
<MenuItem component={Link} to='/catalog' selected={'/catalog' === pathname} className="menuItem" className={classes.menuItemColor}>
Каталог
</MenuItem>
</li>
<li>
<MenuItem component={Link} to='/company' selected={'/company' === pathname } className="menuItem" className="">
Компания
</MenuItem>
</li>
<li>
<MenuItem component={Link} to='/contacts' selected={'/contacts' === pathname} className="menuItem" className="">
Контакты
</MenuItem>
</li>
</ul>
</nav>
<main className={classes.content}>
{ children }
</main>
</Fragment>
</MuiThemeProvider>
</div>
);
}
}
NavRouter.js file:
<BrowserRouter>
<Navigation>
<Switch>
<Route path='/' exact component={ Navigation }></Route>
<Route path='/home' component={ Home }></Route>
</Switch>
</Navigation>
</BrowserRouter>
you can do the following:
create a file called Routes.js
in Routes.js:
export default () => (
<BrowserRouter>
<Switch>
<Route path='/' exact component={ Home }></Route>
<Route path='/cabinet' component={ Cabinet }></Route>
<Route path='/catalog' component={ Catalog }></Route>
<Route path='/company' component={ Company }></Route>
<Route path='/contacts' component={ Contacts }></Route>
</Switch>
</BrowserRouter>
)
in App.js
import Routes from './Routes';
import Navigation from './Navigation'
//inside render
<Navigation>
<Routes />
</Navigation>
Note: to get the current pathName, you have to use a state management solution like Redux.
Or: if you are not familiar with redux, for now instead of pathname in Navigation component you can use window.location.pathname
Here's the way to you need to do it. Separate the header navigation from the other components.
App.js
<Navigation/>
<BrowserRouter>
<Switch>
<Route path='/' exact component={ Home }></Route>
<Route path='/cabinet' component={ Cabinet }></Route>
<Route path='/catalog' component={ Catalog }></Route>
<Route path='/company' component={ Company }></Route>
<Route path='/contacts' component={ Contacts }></Route>
</Switch>
</BrowserRouter>
I have solved my problem by creating Root.js file, where I have placed my components
class Root extends Component {
render() {
return (
<div>
<MainNavigation />
<TopNav />
{this.props.children}
</div>
);
}
}
And in App.js file I have placed this:
<BrowserRouter>
<Root>
<Route path='/' exact component={ Home } />
<Route path='/cabinet' component={ Cabinet } />
<Route path='/catalog' component={ Catalog } />
<Route path='/company' component={ Company } />
<Route path='/contacts' component={ Contacts } />
</Root>
</BrowserRouter>

How to hide navbar in login page in react router

I want to hide the navbar in a login page.
I did it actually, but I can't see the navbar on other pages.
This code is part of My App.jsx file.
I make history in App's state. And I hide navbar, when this pathname is '/' or '/login'.
It works!
But then I typed the ID and password, and clicked the login button, got 'success' result, and navigated to '/main'.
Now I can't see navbar in main component too.
How can I do this?
Sorry about my short english. If you can't understand my question, you can comment.
constructor(props) {
super(props);
this.state = {
isAlertOpen: false,
history: createBrowserHistory(),
};
this.toggleAlert = this.toggleAlert.bind(this);
}
<BrowserRouter>
<div className="App">
{this.state.history.location.pathname === '/' || this.state.history.location.pathname === '/login' ? null
: <Header toggleAlert={this.toggleAlert} />}
<div className="container">
{this.state.history.location.pathname === '/' || this.state.history.location.pathname === '/login' ? null
: <Navbar />}
<Route exact path="/" render={() => <Redirect to="/login" />} />
<Route path="/login" component={Login} />
<Route path="/main" component={Main} />
<Route path="/user" component={User} />
<Route path="/hw-setting" component={Setting} />
<Route path="/hw-detail/:id" component={HwDetail} />
<Route path="/gas-detail/:id" component={GasDetail} />
{this.state.isAlertOpen ? <Alert /> : null}
</div>
</div>
</BrowserRouter>
login(event) {
event.preventDefault();
userService.login(this.state.id, this.state.password).subscribe(res => {
if (res.result === 'success') {
global.token = res.token;
this.props.history.push('/main');
} else {
alert(`[ERROR CODE : ${res.statusCode}] ${res.msg}`);
}
});
You could structure your Routes differently so that the Login component doesn't have the Header Like
<BrowserRouter>
<Switch>
<div className="App">
<Route exact path="/(login)" component={LoginContainer}/>
<Route component={DefaultContainer}/>
</div>
</Switch>
</BrowserRouter>
const LoginContainer = () => (
<div className="container">
<Route exact path="/" render={() => <Redirect to="/login" />} />
<Route path="/login" component={Login} />
</div>
)
const DefaultContainer = () => (
<div>
<Header toggleAlert={this.toggleAlert} />
<div className="container">
<Navbar />
<Route path="/main" component={Main} />
<Route path="/user" component={User} />
<Route path="/hw-setting" component={Setting} />
<Route path="/hw-detail/:id" component={HwDetail} />
<Route path="/gas-detail/:id" component={GasDetail} />
{this.state.isAlertOpen ? <Alert /> : null}
</div>
</div>
)
As of the latest release of React Router v6, it is no longer possible to pass a <div> component inside the Routes (v6) aka Switch(v5 or lower) to render a Navbar. You will need to do something like this:
Create two Layout components. One simply renders a Nav and the other one does not. Suppose we name them
<WithNav />
<WithoutNav />
You will need to import <Outlet /> from the React router and render inside the Layout components for the routes to be matched.
Then in your App or where ever you have your Router you will render like below ....
// WithNav.js (Stand-alone Functional Component)
import React from 'react';
import NavBar from 'your navbar location';
import { Outlet } from 'react-router';
export default () => {
return (
<>
<NavBar />
<Outlet />
</>
);
};
// WithoutNav.js (Stand-alone Functional Component)
import React from 'react';
import { Outlet } from 'react-router';
export default () => <Outlet />
// your router (Assuming this resides in your App.js)
<Routes>
<Route element={<WithoutNav />}>
<Route path="/login" element={<LoginPage />} />
</Route>
<Route element={<WithNav />}>
<Route path="/=example" element={<Example />} />
</Route>
</Routes>
LoginPage will not have a nav however, Example page will
Simplest way is use div tag and put components in which you want navbar and put login route component outside div tag:
<div className="App">
<Router>
<Switch>
<Route exact path="/" component={Login} />
<div>
<NavBar />
<Route exact path="/addproduct" component={Addproduct}></Route>
<Route exact path="/products" component={Products}></Route>
</div>
</Switch>
</Router>
</div>
Put the Route with path="/" below every other routes :
<Switch>
<Route path="/login" component={Login} />
<Route path="/" component={Home} />
</Switch>
It will work.
I'm was trying to solve this problem, what i did was add component helmet, to install it use : yarn add react-helmet --save.
import {Helmet} from 'react-helmet';
<Helmet>
<script src="https://kit.fontawesome.com/.....js" crossorigin="anonymous"></script>
</Helmet>
The accepted answer has problem if you need to add other default route within the switch if no other route matches, e.g., 404 page, not found page.
I ended up using simple css to hide navigation bar inside my login page.
class LoginPage extends React.Component<>{
...
// Hide navigation bar in login page. Do it inside ComponentDidMount as we need to wait for navbar to render before hiding it.
componentDidMount(){
document.getElementById('navigation-bar')!.style.display = "none";
}
componentWillUnmount(){
document.getElementById('navigation-bar')!.style.display = "flex";
}
render(){
return(
// your login/signup component here
...
)
}
}

Categories