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>
)
}
}
Related
I am running an issue where, regardless of what URL I am putting into my browser, I keep getting routed to my main page. I've posted the code below for you to take a look, but my goal is to have my browser take me to my drivers.jsx component when the URL is localhost:3000/drivers. Currently, when I go to localhost:3000/drivers, it renders my _app.jsx component instead :(. Can someone help me understand why I can never render the Drivers component (in drivers.jsx) when I am at localhost:3000/drivers?
index.jsx:
import { BrowserRouter as Router, Routes, Switch, Route } from 'react-router-dom';
import MyApp from './_app.jsx';
import Drivers from './drivers.jsx'
import React, { Component } from 'react'
import { Link } from "../routes.js"
class Home extends Component {
render() {
return (
<Router>
<Switch>
<Route exact path='/drivers' element = {<Drivers />}> </Route>
<Route exact path='/' element = {<MyApp />}> </Route>
</Switch>
</Router>
);
}
}
export default Home;
_app.jsx
import React, { Component } from 'react';
import { useLoadScript } from '#react-google-maps/api';
import Map from '../components/map.jsx';
import "../styles/globals.css";
const MyApp = () => {
const libraries = ['places'];
const {isLoaded} = useLoadScript({
googleMapsApiKey: XXXXXXXXXXXXXX,
libraries
});
if (!isLoaded) return <div>Loading...</div>;
return (
<Map />
);
}
export default MyApp;
drivers.jsx
import React, { Component } from 'react';
class Drivers extends Component {
render() {
return (
<div>TEST</div>
);
}
}
export default Drivers;
I've tried putting the routing logic inside _app.jsx instead, but that causes an incredible amount of errors. My thought is index.js should host all the routing logic, but it shouldn't keep rendering MyApp instead of Drivers when the route is "localhost:3000/drivers".
if your react-router-dom version is
6.4.3
then the switch component dosen't work try changing code to this
instead of using Switch. wrap Route inside Routes
<Router>
<Routes>
<Route path='/drivers' element = {<Drivers />}> />
<Route exact path='/' element = {<MyApp />}> />
</Routes>
</Router>
like this
I am just starting to learn React from this tutorial. I created components and imported them on my App.js.
However, I noticed that the components are not showing up when I run npm start (i.e. "Welcome to Create Todo Component!!" does not appear). I am also not receiving any error messages. Am I doing something wrongly?
Thanks in advance!
App.js
...
import CreateTodo from "./components/create-todo.component";
import EditTodo from "./components/edit-todo.component";
import TodosList from "./components/todos-list.component";
class App extends Component {
render() {
return (
<Router>
<div className="container">
...
<Route path="/" exact component={TodosList} />
<Route path="/edit/:id" component={EditTodo} />
<Route path="/create" component={CreateTodo} />
...
create-todo.component.js
import React, { Component } from 'react';
export default class CreateTodo extends Component {
render() {
return (
<div>
<p>Welcome to Create Todo Component!!</p>
</div>
)
}
}
You need to actually render your app to the DOM in order for it to display on screen, do you do that? Something like this:
ReactDOM.render(
<App/>,
document.getElementById('root')
);
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>
);
}
};
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;
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} />