Navigate between main content components using react-router-dom within nested components - javascript

In this case, there is an App component which has a Header component which renders one header if the user is logged in and one if not. There is also an Access component which renders either a Landing component if user is not logged in or Dashboard if the user is logged in. The user has access to all routes if logged in. How do I render components using react-router-dom if the user is on the Dashboard component? Currently, LeftNav should always be in view while the components in the main-content className toggle based on the route. Currently only the LeftNav and MainContent components work on "/", if navigated to /test or /test/new neither the LeftNavorTestComponentrender, however theHeadercomponent is still rendering correctly. What am I doing wrong here or how is this toggling betweenmain-content` components achieved?
import { BrowserRouter, Route } from "react-router-dom";
import Header from "./Header";
import Access from "./Access";
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<div>
<Header />
<Route exact path="/" component={Access} />
</div>
</BrowserRouter>
</div>
);
}
};
export default App;
////////////////////////////////
import Landing from "./Landing";
import Dashboard from "./Dashboard";
class Access extends Component {
renderContent() {
switch (this.props.auth) {
case null:
return;
case false:
return (
<Landing />
);
default:
return (
<Dashboard />
);
}
}
render() {
return (
<div>
{this.renderContent()}
</div>
);
}
}
export default Access;
////////////////////////////////
import { Switch, Route } from "react-router-dom";
import LeftNav from "./dashboard/LeftNav";
import MainContent from "./dashboard/MainContent";
import TestContent from "./dashboard/TestContent";
import TestContentNew from "./dashboard/TestContentNew";
class Dashboard extends Component {
render() {
return (
<div>
<div className="dashboard-wrapper" style={dashboardWrapper}>
<LeftNav />
<div className="main-content">
<Switch>
<Route path="/" component={MainContent} />
<Route path="/test" component={TestContent} />
<Route path="/test/new" component={TestContentNew} />
</Switch>
</div>
</div>
</div>
);
}
};
export default Dashboard;

Issue
The main Route in your application only ever matches and renders a route when it exactly matches "/", so when you navigate to another path it ceases to match.
Solution
I don't see where you pass auth as a prop to Access, but since it handles authentication and renders your actual routes you can simply just render it instead of a Route in App. It will always be rendered by the router and display either the landing page or the dashboard.
import { BrowserRouter, Route } from "react-router-dom";
import Header from "./Header";
import Access from "./Access";
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<div>
<Header />
<Access />
</div>
</BrowserRouter>
</div>
);
}
};

Related

How do I Link Components correctly using React Router?

I am using React and React Router to try and link my components together for a project. I would like to link off a picture from the Home page (current component) to a different component.
Currently I can click the picture and it kind of acts like a link (turns blue after I click it sometimes), although it doesn't link to the other component, no errors show and nothing changes in the url bar. Nothing literally happens.
Any thoughts? Here is my code:
import { HashRouter as Router, Route,} from 'react-router-dom';
import Header from './Header'
import PortfolioWorkPage from './Pages/PortfolioWorkPage';
class Home extends React.Component {
render () {
return (
<Router>
<Header />
<h1>PORTFOLIO</h1>
<div className="portfolioPic">
<img src='IMAGES/Portfolio-Pics-Logo.jpg' className='portfolioPic'></img>
<Route path='Portfolio' component={PortfolioWorkPage} />
</div>
</Router>
)
}
}
export default Home
Code with error: react-dom.development.js:17117 The above error occurred in the component: in img (created by Home) in div (created by Home) in Router (created by HashRouter) in HashRouter (created by Home) in Home (created by App) in Router (created by HashRouter) in HashRouter (created by App) in App
import { HashRouter as Router, Route, Link} from 'react-router-dom';
import Header from './Header'
import PortfolioWorkPage from './Pages/PortfolioWorkPage';
class Home extends React.Component {
render () {
return (
<Router>
<Header />
<h1>PORTFOLIO</h1>
<div className="portfolioPic">
<img src='IMAGES/Portfolio-Pics-Logo.jpg' className='portfolioPic'>
<Route exact path='Portfolio'><PortfolioWorkPage /></Route>
</img>
</div>
</Router>
)
}
}
export default Home
Following the comments, here are two implementations using internal state and then a route. In the first you stay at the url path mywebsite.com, in the second the url path becomes mywebsite.com/portfolio. In both cases the image will remain on the page - you are not actually being transferred to a new page, you are just selectively rendering componenets based on the path.
Using internal state:
class Home extends React.Component {
constructor(props){
super(props)
this.state = {
portfolioActive: false
}
}
handleClick = () => {
this.setState({portfolioActive: !this.state.portfolioActive})
}
render () {
return (
<>
<h1>PORTFOLIO</h1>
<div className="portfolioPic">
<img src='IMAGES/Portfolio-Pics-Logo.jpg' className='portfolioPic'
onClick={this.handleClick}/>
</div>
{this.state.portfolioActive ? <PortfolioWorkPage/> : null}
</>
)
}
}
export default Home
Using a route:
import { HashRouter as Router, Route, Link} from 'react-router-dom';
class Home extends React.Component {
render () {
return (
<Router>
<h1>PORTFOLIO</h1>
<div className="portfolioPic">
<Link to="/portfolio">
<img src='IMAGES/Portfolio-Pics-Logo.jpg' className='portfolioPic'/>
</Link>
</div>
<Route exact path="/portfolio">
<PortfolioWorkPage />
</Route>
</Router>
)
}
}
export default Home
You can use the Link or NavLink component provided by react router.
import { Link } from 'react-router-dom';
<Link to="/some-url"/>
<Router>
<div>
<Route exact path="/some-url">
<MyComponentWithImage />
</Route>
</div>
</Router>

React Where to place login page for a one page app with a side menu

I have a react web app with a sidemenu. Whenever a user clicks on the link in the sidemenu, they are routed to a page that is rendered at the right side of the sidemenu. My question is, how do I do login for such a usecase seeing as any page I route to renders to the right of the sidemenu. I want the login page to be full screen without the side menu showing. This is what App.js looks like.
import React, { Component } from "react";
import { HashRouter } from "react-router-dom";
import Navigation from "./pages/General/components/Navigation";
import SideMenu from "./pages/General/components/SideMenu";
import "../src/css/App.css";
class App extends Component {
render() {
return (
<div>
<HashRouter>
<div className="main-wrapper">
<SideMenu />
<Navigation />
</div>
</HashRouter>
</div>
);
}
}
export default App;
Here is Navigation.js
import React from "react";
import { Route } from "react-router-dom";
import CalendarPage from "../../Calendar/CalendarPage";
import DoctorsList from "../../Doctors/DoctorsList";
import PatientsList from "../../Patients/PatientsList";
import AdminUsersList from "../../AdminUsers/AdminUsersList";
import SpecialitiesList from "../../Specialities/SpecialitiesList";
const Navigation = () => {
return (
<div className="mainarea">
<Route exact path="/" component={CalendarPage} />
<Route exact path="/scheduler" component={CalendarPage} />
<Route exact path="/doctors" component={DoctorsList} />
<Route exact path="/patients" component={PatientsList} />
<Route exact path="/admin-users" component={AdminUsersList} />
<Route exact path="/specialities" component={SpecialitiesList} />
</div>
);
};
export default Navigation;
The best solution I can figure out in terms of a clean design, is to implement another router in your App.jsx, because you are implementing the routing inside your component, and you need another one for your login page.
Then, your App.jsx could be like this:
import React, { Component } from "react";
import { Redirect, Route, Switch } from "react-router-dom";
import LogIn from "./pages/General/components/Login";
import HomePage from "./pages/General/components/HomePage";
import "../src/css/App.css";
class App extends Component {
render() {
return (
<div>
<Switch>
<Route path={'/login'} component={LogIn} />
<Route path={'/'} component={HomePage} />
<Redirect to="/" />
</Switch>
</div>
);
}
}
export default App;
Then, for your HomePage do the following
import React, { Component } from "react";
import { HashRouter } from "react-router-dom";
import Navigation from "./pages/General/components/Navigation";
import SideMenu from "./pages/General/components/SideMenu";
import "../src/css/App.css";
class HomePage extends Component {
render() {
return (
<div>
<HashRouter>
<div className="main-wrapper">
<SideMenu />
<Navigation />
</div>
</HashRouter>
</div>
);
}
}
export default HomePage;
I hope it helps!
Here is my solution, it not exactly a solution, but it will give you a basic idea on how to implement this.
The idea is to place the Login component in app.js, and conditionally display it if the user is logged in.
You will have to pass a handler function to login component through which you will be able to control app.js state.
When login will be sucessfull, u can show the Navigation and Sidemenu component.
import { Fragment } from "react";
import Login from "path/to/login";
class App extends Component {
state = { isLoggedIn: false };
loginHandler = () => {
this.setState({
isLoggedIn: true
});
};
render() {
return (
<div>
<div className="main-wrapper">
{isLoggedIn ? (
<Fragment>
<SideMenu />
<Navigation />
</Fragment>
) : (
<Login loginHandler={this.loginHandler} />
)}
</div>
</div>
);
}
}
Also you need write a separate router file, which will contain the main app.
This is used to show the app component when navigated to /
import React from 'react';
import { HashRouter, Route } from 'react-router-dom';
import App from './app';
const MainRoute = () => (
<HashRouter>
<Route path="/" component={App} />
</HashRouter>
);
export default MainRoute;

React Router doesn't display component when route is matched (but render works)

I am trying to learn React and using Create-React-App to experiment.
Today I was trying to learn how to use React Router, but I couldn't make it work.
Here is my code: (App.js)
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter as Router, Route, Link, NavLink, Switch } from 'react-router-dom'
import { Navbar, Jumbotron, Button } from 'react-bootstrap';
class App extends Component {
render() {
const baseUrl = process.env.PUBLIC_URL;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">React Star Wars Table Test</h1>
</header>
<Router>
<div>
<NavLink to={baseUrl + '/Foo'}>Foo</NavLink> <NavLink to={'/Bar'}>Bar</NavLink>
<hr />
<Switch>
<Route path="/" exact render={() => (<h1>HOME</h1>)} />
<Route path={baseUrl + "/Foo"} exact Component={Foo} />
<Route path='/Bar' exact Component={Bar} />
</Switch>
</div>
</Router>
</div>
);
}
}
class Foo extends Component {
render() {
return (
<p>Foo!</p>
);
}
}
class Bar extends Component {
retnder(){
return (
<h1>Bar!</h1>
);
}
}
export default App;
The issue is that the routes don't display the components when they match the URL (either clicking on the NavLinks or manually typing the URL).
The base ('/') route works and displays the HOME H1.
I know the routes are matching because if I try to use the render attribute for all the routes, it works.
No compile errors, no console errors.
The sample code contains the Switch tag, but I have tried also
without, same result.
The sample code has a NavLink and a Route with
a baseUrl const and one without, I have tried either way (none, both,
one yes and one not), same result.
The prop of Route that takes a component is called component, not Component with a capital c.
<Route path='/Bar' exact component={Bar} />

how to change exact path after successful login

i am making a login page that redirect the user after a successful login to home page i am using react router dom i tried to look for a simple way to do it but i couldn't find :
import Authen from './Pages/Authen';
import Home from './Pages/Home';
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
class App extends Component {
render() {
return (
<div className="App">
<Router>
<div>
<ul>
</ul>
<Route exact path="/" component={Authen}/>
<Route path="Home" component={Home}/>
</div>
</Router>
</div>
thank you for your help i really appreciate it :)
login page that redirect the user after a successful login to home
page
Use the withRouter higher order component that comes with react-router-dom. It will give your component acess to the history prop. With the history prop you can push to any new URL.
import React from 'react'
import {withRouter} from 'react-router-dom'
class Authen extends React.Component {
onLogin = () => {
// also other authentication code
this.props.history.push('/home')
}
render() {
return (
<button onClick={() => this.onLogin()}> Login </button>
)
}
}
export default withRouter(Authen);

Get properties from Routes

I'm failing at passing a property from a <Route />
Here is some code :
./app.jsx (main app)
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, IndexRoute } from 'react-router'
import App from './components/app'
import Home from './components/home'
import About from './components/about'
render((
<Router>
<Route path="/" component={App}>
<IndexRoute component={Home} title="Home" />
<Route path="about" component={About} title="About" />
</Route>
</Router>
), document.getElementById('app'))
./components/app.jsx
import React from 'react';
import Header from './template/header'
class App extends React.Component {
render() {
return (
<div>
<Header title={this.props.title} />
{this.props.children}
</div>
)
}
}
export default App
./components/template/header.jsx
import React from 'react'
class Header extends React.Component {
render() {
return (
<span>{this.props.title}</span>
)
}
}
export default Header
When I click on my home route* I want my Header component to display Home.
When I click on my about route I want my Header component to display About.
At this point, my Header components displays nothing. this.props.title is undefined in my App component.
Looks like you can't pass an attribute from a <Route />
Is there a way to achieve this?
Or is there another way? For instance, can you get something from the children element (this.props.children.title or something like that) ?
It looks like the route injects a routes property with a list of the matching routes. The last route in the list has the props you specify. See http://codepen.io/anon/pen/obZzBa?editors=001
const routes = this.props.routes;
const lastRoute = routes[routes.length - 1];
const title = lastRoute.title;
I'd hesitate a little to use this, since routes is not documented in the Injected Props, so I don't know how reliable it is across version updates. A simpler option, though not as legible, would be to use this.props.location.pathname and maintain a lookup table for titles.
The best and most flexible option is probably the boilerplate-heavy one, where you define the template and then reuse it across components:
class Template extends React.Component {
render() {
return (
<div>
<Header title={this.props.title} />
{this.props.children}
</div>
)
}
}
class About extends React.Component {
render() {
return (
<Template title="About">
Some Content
</div>
)
}
}

Categories

Resources