I have a router set up in my App.js as follows:
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
import NavBar from './nav-bar';
import Landing from './landing-page';
import Dashboard from './dashboard';
import Analysis from './analysis';
import '../style.scss';
const App = (props) => {
return (
<Router>
<NavBar />
<Switch>
<Route exact path="/" component={Landing} />
<Route path="/dashboard/:prodID/search" component={Dashboard} />
<Redirect from="/dashboard/:prodID" to="/dashboard/:prodID/search" />
<Route path="/dashboard/:prodID/analyze" component={Analysis} />
<Route component={() => (
<div id="error">
<h1>404 ERROR</h1>
<h2>Page not found</h2>
</div>
)}
/>
</Switch>
</Router>
);
};
export default App;
and my NavBar component is set up as follows:
import React, { Component } from 'react';
import { NavLink, withRouter } from 'react-router-dom';
import { Navbar, Nav } from 'react-bootstrap';
import '../style.scss';
class NavBar extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<Navbar id="nav-bar" bg="dark" variant="dark">
<Navbar.Brand href="/">
My Project
</Navbar.Brand>
<Navbar.Collapse id="responsive-navbar-nav" className="justify-content-end">
<Nav>
<NavLink to="/dashboard/:prodID/search">Search</NavLink>
<NavLink to="/dashboard/:prodID/analyze">Analyze</NavLink>
</Nav>
</Navbar.Collapse>
</Navbar>
);
}
}
export default withRouter(NavBar);
I have two things that I'm trying to figure out:
I want to be able to access the prodID route param within my NavBar component so that when a user clicks on the route, it will take the valid prodID and render the route correctly.
I want to only display the NavLinks in NavBar if the user is on a route that has the prodID param. If they're on the home route / for example, the links wouldn't show up. But if they're on the route /dashboard/[valid prodID]/search, the links would show up.
How do I go about implementing this? I've looked at other posts on SO dealing with route params and nav bars, but none of them have answered my question. Any help is appreciated.
I believe you would have to move your navbar under each of the routes, so that it can be re-rendered and grab the correct params when the path changes.
In order to achieve it, you can create the Layout component which will wrap the component you pass and add a navbar to it:
// Layout.jsx
import React from "react";
import NavBar from './nav-bar';
export const Layout = () => {
return (
<div>
<Navbar />
<div>{children}</div>
</div>
);
};
Then in your App, you can wrap each component within the routes with the Layout component like so
// App.jsx
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
Redirect
} from "react-router-dom";
import NavBar from "./nav-bar";
import Landing from "./landing-page";
import Dashboard from "./dashboard";
import Analysis from "./analysis";
import { Layout } from "./Layout";
import "../style.scss";
const App = props => {
return (
<Router>
<Switch>
<Route exact path="/">
<Layout>
<Landing />
</Layout>
</Route>
<Route path="/dashboard/:prodID/search">
<Layout>
<Dashboard />
</Layout>
</Route>
<Redirect from="/dashboard/:prodID" to="/dashboard/:prodID/search" />
<Route path="/dashboard/:prodID/analyze">
<Layout>
<Analysis />
</Layout>
</Route>
<Route
component={() => (
<div id="error">
<h1>404 ERROR</h1>
<h2>Page not found</h2>
</div>
)}
/>
</Switch>
</Router>
);
};
export default App;
This approach would help you achieve your second goal. Since the navbar is now nested under each route, you can easily fetch the params from the path and conditionally render the links, like so:
// NavBar.jsx
import React from "react";
import { NavLink, useParams } from "react-router-dom";
import { Navbar, Nav } from "react-bootstrap";
import "../style.scss";
const NavBar = () => {
const { prodID } = useParams();
return (
<Navbar id="nav-bar" bg="dark" variant="dark">
<Navbar.Brand href="/">My Project</Navbar.Brand>
<Navbar.Collapse
id="responsive-navbar-nav"
className="justify-content-end"
>
<Nav>
{prodID && (
<NavLink to={`/dashboard/:${prodID}/search`}>Search</NavLink>
)}
{prodID && (
<NavLink to={`/dashboard/:${prodID}/analyze`}>Analyze</NavLink>
)}
</Nav>
</Navbar.Collapse>
</Navbar>
);
};
export default NavBar;
I haven't tested it, but it should help you with your issues.
Related
Soo, im new on react js framework. im trying to make an navigation link. but when it clicked, it re-render the previous component . codes below
import React, { Component } from 'react';
import {Card, Button , ListGroup } from 'react-bootstrap'
import { Route, Link, BrowserRouter,Routes } from 'react-router-dom'
import Mappage from '../mapPage';
import Home from '../home';
import 'bootstrap/dist/css/bootstrap.min.css';
class FloorOne extends Component {
state = {
}
render() {
// const floors = [1,2,3,4,5,6,7];
return (
<BrowserRouter>
<div className='cardContainer'>
<ListGroup as ="ul" className='floorCard'>
<ListGroup.Item as ="li">
<Link to="/mapPage"> link to map</Link>
</ListGroup.Item>
<ListGroup.Item as ="li">
<Link to="/home"> buttom home</Link>
</ListGroup.Item>
<Routes >
<Route path="/mapPage" element={ <Mappage/>}/>
<Route path="/home" element={<Home/>}/>
</Routes>
</ListGroup>
</div>
</BrowserRouter>
);
}
}
export default FloorOne;
i use route and routes and link it to a component as i thought its a "page". but the previous component still renderd on the page other page that i navigate (either mappage or hompage)
this is homepage
import React, { Component } from 'react';
function Home() {
return <div>
<h1>this is homepage</h1>
</div>
;
}
export default Home;
First of all, React is a library, not a framework.
And your Link components always should be in the children of Routes component. Try using Link in Mappage or home. There it should work
Your FloorOne Component should be like this
import React, { Component } from 'react';
import { Route, Link, BrowserRouter,Routes } from 'react-router-dom'
import Mappage from '../mapPage';
import Home from '../home';
import 'bootstrap/dist/css/bootstrap.min.css';
class FloorOne extends Component {
state = { }
render() {
// const floors = [1,2,3,4,5,6,7];
return (
<BrowserRouter>
<Routes >
<Route path="/mapPage" element={<Mappage />}/>
<Route path="/home" element={<Home />}/>
</Routes>
</BrowserRouter>
);
}
}
Your Home Component can be like this
import React, { Component } from 'react';
import { Card, Button , ListGroup } from 'react-bootstrap';
import { Link } from 'react-router-dom'
function Home() {
return (
. <div>
<ListGroup as="ul" className='floorCard'>
<ListGroup.Item as="li">
<Link to="/mapPage"> link to map</Link>
</ListGroup.Item>
<ListGroup.Item as="li">
<Link to="/home"> buttom home</Link>
</ListGroup.Item>
</ListGroup>
</div>
);
}
export default Home;
Use exact in your Route
<Routes>
<Route exact path="/mapPage" element={ <Mappage/>}/>
<Route exact path="/home" element={<Home/>}/>
</Routes>
I'm trying to create a website in react and am using router-dom to have the correct url showing.
I have a navbar that links to an about page using Link to="" and then using Switch and Route to display the component for the correct path, but it doesn't work.
Not sure if I missed anything here but I can't manage to display any components.
This is my PageContainer
import React from "react";
import { Route, Switch } from "react-router-dom";
import Alphabet from "./Alphabet";
import About from "./About";
export default class PageContainer extends React.Component {
render() {
return (
<section className="pagecontainer">
<Switch>
<Route exact path="/omoss">
<About />
</Route>
<Route exact path="/">
<Alphabet />
</Route>
</Switch>
</section>
);
}
}
This is my navbar
import React from "react";
import { Link } from "react-router-dom";
export default class Navbar extends React.Component {
render() {
return (
<section>
<section className="navbar">
<Link to="/">Hem</Link>
<Link to="/omoss">OM OSS</Link>
</section>
</section>
);
}
}
UPDATE:
Removed BrowserRouter from both components above.
Changed App.js to below.
App.js
import React from "react";
import "./App.css";
import { BrowserRouter } from "react-router-dom";
import Navbar from "./components/Navbar";
import PageContainer from "./components/PageContainer";
function App() {
return (
<BrowserRouter>
<section className="App">
<Navbar />
<PageContainer />
</section>
</BrowserRouter>
);
}
export default App;
Still not working though. The url changes but the components doesn't show.
UPDATE 2
Think I solved it when I removed two other components that where showing in Switch inside PageContainer but weren't in a Route. I had removed them before uploading here but forgot them in my code
You have two individual <BrowserRouter /> components, each with its own state. I suggest that you move the <BrowserRouter /> component to a common ancestor of both <Navbar /> and <PageContainer /> so that they can share the same history object.
For example, remove the BrowserRouter from your components and place it higher in the component hierarchy. Now, both <Navbar /> and <PageContainer /> are in the scope of the same <BrowserRouter />
function App() {
return (
<BrowserRouter>
<Navbar />
<PageContainer />
</BrowserRouter>
);
}
Try to add BrowserRouter in App.js
import React from "react";
import "./App.css";
import { BrowserRouter } from "react-router-dom";
import Navbar from "./components/Navbar";
import PageContainer from "./components/PageContainer";
function App() {
return (
<BrowserRouter>
<section className="App">
<PageContainer />
<Navbar />
</section>
</BrowserRouter>
);
}
export default App;
This is a simplified reproduction of the problem: The child with the nested URL does not render.
My file structure is basically this:
-App
--Home
--Pageone
---Childone
I can render Home or Pageone from App, then I can render Home or Pageone from Pageone or Home respectively, but I cannot render Childone from its 'parent page' Pageone. I am not quite sure what is done wrong.
The code is shared below, and this sandbox
App.jsx
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Pageone from "./Pageone";
import Home from "./Home";
export default function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/pageone">
<Pageone />
</Route>
</Switch>
</BrowserRouter>
);
}
Home.jsx
import { Link } from "react-router-dom";
const Home = () => {
return (
<div>
<p>This is HOME!</p>
<Link to="/pageone">Pageone</Link>
</div>
);
};
export default Home;
Pageone.jsx
import { Link, Route, useRouteMatch } from "react-router-dom";
import Childone from "./Childone";
const Pageone = () => {
const { path, url } = useRouteMatch();
return (
<div>
<Route exact path={path}>
<PageoneContent url={url} />
</Route>
<Route exact path={path + "/childone"}>
<Childone />
</Route>
</div>
);
};
const PageoneContent = (props) => {
return (
<div>
<p>This is pageone!</p>
<Link to="/">Go back Home</Link>
<br />
<Link to={props.url + "/childone"}>Go to Child One</Link>
</div>
);
};
export default Pageone;
Childone.jsx
import { Link } from "react-router-dom";
const Childone = () => {
return (
<div>
<p>This is Child one!</p>
<Link to="/">Go back Home</Link>
</div>
);
};
export default Childone;
As far as I know you need to use another Switch for routes, otherwise react will have no idea how to match that route path.
<div>
<Route exact path={path}>
Should be:
<Switch>
<Route exact path={path}>
I've tried everything but fail to render component when URL changes. No error messages nothing, react-redux is installed but not using it yet, so it can't be the problem. When I check it from to Google chrome React dev tools, nothing happens, there is no match, history vs anything. I couldn't find a solution, is there any way to make it work?
https://codesandbox.io/s/vm3x9n4k67
Here is my NavBar.js. I import NavLink from react-router-dom and implement these
import React from 'react'
import classes from "./NavBar.css";
import { NavLink } from 'react-router-dom';
const NavBar = (props) => {
return (
<div className={classes.NavBar}>
<h1 className={classes.NavBar_list} >foodbase</h1>
<ul className={classes.NavBar_list}>
<NavLink to="/auth"> <li className={classes.NavBar_list_item}>Signin</li></NavLink>
<NavLink to="/"><li className={classes.NavBar_list_item}>Main Page</li></NavLink>
</ul>
</div>
)
}
export default NavBar
this is my Layout.js render property:
render() {
let recipes = [];
if (this.state.recipes.length > 0) {
recipes = this.state.recipes;
}
return (
<div>
<NavBar/>
<SearchBox
onChangeHandler={this.onChangeHandler}
value={this.state.inputValue}
onSearchClick={this.onClickedHandler} />
<section className={classes.SearchSection}>
<ul className={classes.SearchResultArea}>
<SearchResults
Results={recipes}
></SearchResults>
</ul>
</section>
</div>
)
}
and finally app.js:
import React, { Component } from 'react';
import { Switch, Route, BrowserRouter, withRouter } from 'react-router-dom';
import Auth from './components/Auth/Auth';
import SearchBox from './components/SearchBox/SearchBox';
import Layout from './containers/Layout/Layout';
import './App.css';
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<Switch>
<Layout>
<Route path="/auth" component={Auth} />
<Route path="/" exact component={SearchBox} />
</Layout>
</Switch>
</BrowserRouter>
</div>
);
}
}
export default withRouter(App);
I assume that you need to put your Route components directly into Switch and don't forget to render children in Layout. So try this:
app.js:
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<Layout>
<Switch>
<Route path="/auth" component={Auth} />
<Route path="/" exact component={SearchBox} />
</Switch>
</Layout>
</BrowserRouter>
</div>
);
}
}
Layout.js
render() {
// ...
return (
<div>
<NavBar />
{ this.props.children } // <-- your route specific components
</div>
)
}
I am new to React and having issues with router. I am just learning from this tutorial: https://medium.com/#thejasonfile/basic-intro-to-react-router-v4-a08ae1ba5c42
Below is the code that is being called from my index.html. When I click on the link 'Show the list', the url changes from localhost:8080 to localhost:8080/list but doesn't really change the context of the page. I am not sure what is going or what I am doing wrong here. Any ideas?
Scripts.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Title, App} from './Components/App';
import { BrowserRouter as Router, Route } from 'react-router-dom';
ReactDOM.render(
<Router>
<div>
<Route exact path="/" component={Title} />
<Route path="/list" component={App} />
</div>
</Router>
, document.getElementById('app'));
App.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
const Title = () => {
return (
<div className="title">
<h1>React Router demo</h1>
<Link to="/list">
<button>Show the List</button>
</Link>
</div>
)};
const List = () => {
return (
<div className="nav">
<ul>
<li>list item</li><li>list item</li></ul><Link to="/"><button>Back Home</button></Link></div>)
}
module.exports = {
Title,
List
};
I refactored your code a bit, you should not render the App component for a single page rather your app component should have all the routes like how I made it below. Then as needed add Link throughout your components when you need to navigate and then add the routes in App respectively.
import React, { Component } from 'react';
import { render } from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { Link } from 'react-router-dom';
class App extends Component {
constructor() {
super();
}
render() {
return (
<Router>
<div>
<Route exact path='/home' render={()=> <Title />} > </Route>
<Route exact path='/list' render={() => <List />} > </Route>
</div>
</Router>
);
}
}
const Title = () => {
return (
<div className="title">
<h1>React Router demo</h1>
<Link to="/list">
<button>Show the List</button>
</Link>
</div>
)};
const List = () => {
return (
<div className="nav">
<ul>
<li>list item</li><li>list item</li></ul><Link to='/home'><button>Back Home</button></Link></div>)
}
render(<App />, document.getElementById('app'));
document.getElementById is usually root looks like you changed it to app which is fine.