React-router - hide component from main URL? - reactjs

I have this router:
ReactDOM.render((
<Router>
<div>
<Route path="/" component={Auth} />
<Route path="/register" component={RegisterForm} />
<Route path="/login" component={LoginForm} />
</div>
</Router>
), document.getElementById('app'));
And that's the auth component:
class Auth extends React.Component {
render() {
return (
<section className="auth">
<header>
<h2>Login / Register</h2>
</header>
<ul className="auth__list">
<li className="button auth__button"><Link to="/login">Login</Link></li>
<li className="button auth__button"><Link to="/register">Register</Link></li>
</ul>
</section>
);
}
}
When I go to http://my-project/ it shows Auth component.
But when I click on "Register" or "Login" links it's showing "RegisterForm" or "LoginForm" components below the Auth component, while in my opinion /register should show only RegisterForm and /login should show only /LoginForm.
My question is:
why is the "Auth" component being rendered on /register and /login by default?
what's the best way to get rid of it on these pages?
Unfortunately react-router's webpage doesn't help, because they stick navigations above every example and it's confusing to me :(
Thanks a lot.
UPDATE
That's how I import the router, maybe that's the issue?
import React from 'react';
import ReactDOM from 'react-dom';
(...)
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'

Related

React not rendering Route Components

I am building a consumer facing app with a admin dashboard. I want to keep the routing separate for them and so trying to delegate :-
App.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
//styles
import './style/bootstrap/bootstrap.scss';
//apps
import Mainapp from './mainapp/Mainapp';
import Admin from './admin/Admin';
const MainappContainer = () => (
<Mainapp />
);
const AdminContainer = () => (
<Admin />
);
class App extends Component{
render(){
return (
<Router>
<Switch>
<Route path="/admin" component={AdminContainer}/>
<Route path="/" component={MainappContainer}/>
</Switch>
</Router>
)
}
}
export default App;
Admin.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
//styles
import './admin-style.scss';
//layout
import ControlPanel from './component/layout/ControlPanel';
import Navbar from './component/layout/Navbar';
//pages
import Quote from './component/pages/quote/Quote';
class Admin extends Component{
render(){
return (
<div className="adminWrapper">
<ControlPanel />
<section className="viewPanel">
<Navbar />
<Router>
<Route path="/quote" component={Quote}/>
</Router>
</section>
</div>
)
}
}
export default Admin;
However when I hit the URL
http://localhost:3000/admin/quote
it doesn't seem to load the quote component
Quote.js
import React, { Component } from 'react';
class Quote extends Component {
render() {
return (
<div className="float-right pr-3">
<h3>
Quote Page
</h3>
</div>
)
}
}
export default Quote;
When dealing with nested subroutes, the easiest solution is to use match.
path - (string) The path pattern used to match. Useful for building nested
Routes.
url - (string) The matched portion of the URL. Useful for building
nested Links.
By design, components placed inside a Route's component render method are given several additional props from react-router-dom. Among them are history and match. You can leverage these props to either to match against sub routes and/or to control browser history location.
In addition, you only need one instance of BrowserRouter sitting at the top-level of the application, then you can use Switch to optionally render any main or sub routes. And you don't need to use class components unless you're utilizing state and/or a class field.
A very basic, rudimentary working example of your application:
src/components/Admin/index.js
import React from "react";
import { Switch, Link, Route } from "react-router-dom";
import ControlPanel from "../ControlPanel";
import Quote from "../Quote";
// since Admin is placed inside a Route's component render
// method, it has access to history and match
function Admin({ history, match }) {
return (
<div className="adminWrapper">
<ControlPanel />
<section className="viewPanel">
<Link to={`${match.url}/quote`}>View quote</Link>
<br />
<Switch>
<Route exact path={`${match.path}/quote`} component={Quote} />
</Switch>
</section>
<br />
<button type="button" onClick={() => history.goBack()}>
Go Back
</button>
</div>
);
}
export default Admin;
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
import Admin from "./components/Admin";
const linkStyle = {
padding: "0 10px"
};
function App() {
return (
<BrowserRouter>
<Link style={linkStyle} to="/">
Home
</Link>
<Link style={linkStyle} to="/admin">
Admin
</Link>
<Switch>
<Route path="/admin" component={Admin} />
<Route path="/" render={() => <h1>Main App</h1>} />
</Switch>
</BrowserRouter>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Follow the Nested Routing Example
The main changes you need to do are:
1. Remove the <Router></Router> from Admin component and
2. Prepend match.path to "/quotes", like it is done in Topics component in the example. In the example, Topics is a function component so it is receiving match as function parameter. As your Admin component is class component, you can access it as this.props.match in render method.
<Route path={`${this.props.match.path}/quote`} component={Quote}/>
<Route exact path="/admin" component={AdminContainer}/>
<Route exact path="/admin/quote" component={Quote}/>
This won't route you to /admin/quote instead it will route you to /admin/admin/quote.
Since it is inside admin just /quote is enough
<Route path="/admin" component={AdminContainer}/>
<Route path="/quote" component={Quote}/>

<Link> in React doesn't forward to a new page

Consider the code :
import React from 'react';
import { Link, BrowserRouter } from 'react-router-dom';
import { ReactComponent as Logo } from '../../assets/crown.svg';
import './header.styles.scss';
const Header = () => (
<BrowserRouter>
<div className='header'>
<Link className='logo-container' to='/'>
<Logo className='logo' />
</Link>
<div className='options'>
<Link className='option' to='/shop'>
SHOP
</Link>
<Link className='option' to='/contact'>
CONTACT
</Link>
</div>
</div>
</BrowserRouter>
);
export default Header;
This is a header that I use in my App.
Look like this :
When I click on the crown the URL (in the browser) changes , but the page doesn't change , it stays on the same page.
Same thing happens with the other Links , CONTACT & SHOP.
What's wrong with the <Link> tag ? Why doesn't it forward to the to that's written on the Link tag ?
Did you setup the routes? This would be in AppRouter.js for example:
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path='/' component={Home} exact={true} />
<Route path='/shop' component={Shop} exact={true }/>
<Route path='/contact' component={Contact} exact={true} />
<Route component={ErrorPage} />
</Switch>
</div>
</BrowserRouter>
If you want navigate your user try use NavLink
or add withRouter to component and push them to the other pages
-- NavLink solution :
import { NavLink, BrowserRouter } from 'react-router-dom';
and then in your JSX use this instead
<NavLink className='logo-container' to='/'>
<Logo className='logo' />
</NavLink>
-- push solution:
import { withRouter , BrowserRouter } from 'react-router-dom';
export your component like this
export default withRouter(Header);
then you can use any tags you want and listen at events on them
<p className='logo-container' onClick = {() => props.history.push('/')}>
<Logo className='logo' />
</p>
in order to navigate to different components you have to define routers. So react-router-dom will know what to display.
The other thing is u cannot put BrowserRouter inside the Header component. Component BrowserRouter wraps the history object in the browser and passes it to down to component tree. BrowserRouter is a wrapper. Header should be placed inside the BrowserRouter but not here. just create your Header Component without BrowserRouter.
here is how you should properly implement routing in react.js
in src/omponents folder create your components for routes.
src/component/shop.js:
import React from "react";
const Shop = () => <div>my shop component</div>; //define your component
export default Shop;
create all other components like so including Header but without BrowserRouter. then in src folder create a new directory name routers. inside of it create AppRouter.js
src/routers/AppRouter.js
import { BrowserRouter, Route, Switch } from "react-router-dom";
import React from "react";
import Shop from "../components/Shop";
//import all other routes from components directory.
import Header from "../components/Header"
const AppRouter = () => (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path="/" component={YourHomeComponent} exact={true} />
<Route path="/contact" component={Contact} />
<Route path="/shop" component={Shop} />
<Route component={NotFound} />
</Switch>
</div>
</BrowserRouter>
);
export default AppRouter;
// When react-router sees “Switch” it is going to move through your route definitions in order and it’s going to stop when it finds a match.
finally in app.js
import React from "react";
import ReactDOM from "react-dom";
import AppRouter from "./routers/AppRouter";
ReactDOM.render(<AppRouter />, document.getElementById("app"));

The link is being rendered but not redirecting using <Link>

I have been trying to redirect the page using <Link> and what i have is that the URL changes but the page does not redirect. Only after i refresh the page, it show.
I have searched and found some links:
1. One on the correct syntax
2. i have implemented the link in small HTML
Now here is the part of my Code
App.Js
import React from 'react';
import { Switch , Route , BrowserRouter } from 'react-router-dom';
import HomePage from './section/home';
import Oneup from './section/oneup';
function App() {
return (
<div className="main homepage">
<BrowserRouter>
<div>
<Switch>
<Route path="/" component={HomePage} exact={true} />
<Route path="/oneup" component={Oneup} exact={true} />
</Switch>
</div>
</BrowserRouter>
</div>
);
}
main_content.js
Here i have included <Link>
import React from 'react';
import { BrowserRouter, Link } from "react-router-dom";
class Main_content extends Component {
render() {
return (
<div class="ib-center">
<BrowserRouter>
<Link to="/oneup" class="btn">VIEW CASE</Link>
</BrowserRouter>
</div>
)
}
}
Now i can't figure out where i am going wrong.
the link generated is fine and working when refreshed manually.
Use one BrowerRouter to wrap, you have used BrowerRouter in App.js and main_content.js too
class Main_content extends Component {
render() {
return (
<div class="ib-center">
<div>
<Link to="/oneup" class="btn">VIEW CASE</Link>
</div>
</div>
)
}

React navigation to pages issues

I am trying to navigate to a login page using react router but when the button is clicked, the next page is displayed on the same page without actually navigating to the next page.
Here is my code
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import $ from 'jquery';
import { Login } from './Login';
export class Index extends Component {
render() {
return (
<div>
<div align='center'>
<h3> Project Management System </h3>
</div>
<p>
Here, you can search for the previous B.sc, M.sc and Ph.D projects that have been carried out in the department. <br/><br/>
</p>
<Router>
<div>
<Link to="/login">Continue </Link>
<Route exact path={"/login"} component={Login}/>
</div>
</Router>
</div>
);
}
}
When I click on continue button, it's supposed to show the login page alone, without showing the previous page, but here, it shows both previous page and the login page.
--Edit--
Move your button and info in another Component, call it Home or something similar.
Home.js
import React from "react"
import { Link } from "react-router-dom"
const Home = () => {
return(
<div>
<div style={{textAlign: "center"}}>
<p>Your paragraph</p>
<Link to="/login">Continue </Link>
</div>
</div>
)
}
export default Home
Index.js
now you'll have a cleaner Router
keep all your imports and bring in the Home component
export class Index extends Component {
render() {
return (
<div>
<Router>
<div>
<Switch>
<Route path="/" exact={true} component={Home}>
<Route path="/login" component={Login}/>
</Switch>
</div>
</Router>
</div>
The reason for that behavior is very simple. You wrapped only Login component with the router. You have to create routes with the Switch component to change the views. Here is an example https://codesandbox.io/s/2xqxqpo550

How to link to Routes inside the component rendered by another Route with React Router

i'm trying to use react router in my reactjs app. And I encountered this problem:
This is what i'm trying to do:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import About from '../Pages/About';
import Home from '../Pages/Home';
import Topics from '../Pages/Topics';
import LinkTest from '../Pages/LinkTest';
class AppRouter extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
<Route path="/home" component={LinkTest}/>
</ul>
<hr />
<Route path="/home" component={Home}/>
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
}
}
export default AppRouter;
Ignore "about" and "topic" component, when I click on "Home" link, it should target 2 routes, one will render "LinkTest" and the other renders "Home".
This is what inside "LinkTest":
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class LinkTest extends Component {
render() {
const {match}=this.props;
return (
<div>
<Link to={`${match.url}/Test`}>Link To Test</Link>
</div>
);
}
}
export default LinkTest;
And inside my "Home" component:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Test from './Test';
class Home extends Component {
render() {
const {match} = this.props;
console.log(match.url);
return (
<Router>
<div>
<h2>
Hello from Home page
<Link to={`${match.url}/Test`}>Link To Test</Link>
<Route path={`${match.url}/Test`} component={Test}/>
</h2>
</div>
</Router>
);
}
}
export default Home;
However:
When i click on the link inside "LinkTest" component (which was rendered earlier), the url on the browser is shown "http://localhost:3000/home/Test", but nothing happens.
When i clicked on the link inside "Home" component, (which was rendered the same time as the "LinkTest" using the same link), it showed the same url on the browser: "http://localhost:3000/home/Test", only this time it rendered the "Test" component.
Why does this happen? (what i want to achieve is I want to use the link inside "LinkTest" to render "Test" component inside "Home" component, or something similar).
I hope this is clear enough.
You can do it in following way:
<Route exact path='/a' component={A} />
<Route path='/b' component={B} />
// Following should be router inside Component B
<Route exact path='/b/abc' component={OtherComponent}
If you want I've prepared few react-router 4 examples. These are hosted here. https://github.com/SandipNirmal/react-router-examples
If you need Nested routing inside ComponentB you should add Links for those Routes as well. And use match.url and match.path to build the nested Links and Routes.
const ComponentB = ({ match }) => {
return (
<div>
<div>
<ul>
<li><Link to={`${match.url}/c`}>Component C</Link></li>
// more Links
<li><Link to={`${match.url}/css`}>CSS</Link></li>
<li><Link to={`${match.url}/react`}>React</Link></li>
</ul>
</div>
<div>
<Route path={`${match.path}/c`} component={ComponentC} />
// more nested Routes
<Route path={`${match.path}/css`} render={() => { return <h1>CSS</h1> }}/>
<Route path={`${match.path}/react`} render={() => { return <h1>React</h1> }}/>
</div>
</div>
);
}
Nested routing
Components created via Route will automatically be passed the following prop objects: match, location and history.
Using match you can implement nested Routes. The match object contains the following properties:
params — (object) Key/value pairs parsed from the URL corresponding
to the dynamic segments of the path
isExact — (boolean) true if the entire URL was matched (no trailing characters)
path — (string) The path pattern used to match. Useful for building nested Routes
url — (string) The matched portion of the URL. Useful for building
nested Links
Reference
https://medium.freecodecamp.org/beginners-guide-to-react-router-4-8959ceb3ad58
https://medium.com/#pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf

Resources