i am having trouble with reach router nested routes, I am trying to navigate to / and render page2, but I am stuck on "/" homepage the same page when the route changes to //
<Appjs>
import React from "react";
import "./App.css";
import Homepage from "./Components/Homepage";
import Details from "./Components/Details";
function App() {
return (
<div>
<Router>
<Homepage path="/">
<Details path="details" />
</Homepage>
</Router>
</div>
);
}
export default App;
import React, { Component, useEffect, useState } from "react";
import styled, { isStyledComponent } from "styled-components";
import NavLink from "./NavLink";
import { Link } from "#reach/router";
const Homepage = () => {
const [users, setUsers] = useState([]);
return (
<React.Fragment>
<div className={"container"}>
<Styleddiv>
<h2>Select an Account</h2>
<div style={{ padding: 0 }}>
{Object.values(users).map((item) => (
<Link to={`details/${item.name}`}>
<img src={item.profilepicture} alt="Girl in a jacket"></img>
<span>{item.name}</span>
</Link>
))}
</div>
</Styleddiv>
</div>
</React.Fragment>
);
};
export default Homepage;
Am I missing something while structuring the routes inside the router, Kindly help me
So in Homepage If i click on any Link the route changes to /details but the details page fails to render
https://codesandbox.io/s/billowing-hill-j5gmy?file=/src/Homepage.js
Did you miss your Router import on your App.js file?
import React from "react";
import { Router, Link } from "#reach/router";
import Homepage from "./Homepage";
import Details from "./Details";
export default function App() {
return (
<div>
<nav>
<Link to="/">Home</Link>
<Link to="dashboard">Detail</Link>
</nav>
<Router>
<Homepage path="/" />
<Details path="dashboard" />
</Router>
</div>
);
}
Edit: Code Sand Box
This is how I use nested routes
Code sandbox
In order to nest routes you need to place them in the child component of the route.
The render prop is used instead of component because it stops the inline functional component from being remounted every render, see explanation.
The match object contains the information about how a route matched the URL, so we can have a nested route using the url property which gives us the matched portion of the URL, see explanation.
Related
I have a menu with a "login" link to open to the login page. When I click on the "login" link it does nothing...doesn't open page, just empty click. My expectation was that the login page would be displayed. I am using an existing html template that uses UL lists for the menu. I'd like to keep using the UL list for the menu, if possible, as it fits in the existing CSS and layout of the page nicely.
I've researched react-router-dom, links, routes, etc for the last 3 hours...I can't find a solution for this, I see how others made it work somehow for their project, but when I try the solutions in my project it doesn't work for me...perhaps I've got something out of order? I'm new to react, but have read/watched a bunch of tutorials and would welcome any advice or guidance.
The problem appears to be inside "HeaderMenu.js". I've included the details of the components. thanks in advance.
The rendered anchor tag looks like this after React renders it:
Login
Here is how the project is set up:
Folder Structure
/src/Index.js
/src/App.js
/src/components/Home.js
/src/components/header.js
/src/components/HeaderMenu.js
/src/components/Login.js
Index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
App.js
import './App.css';
import Home from "./components/Home";
function App() {
return (
<>
<Home />
</>
);
}
export default App;
Home.js
import Header from "./header";
import Body from './body';
import Footer from "./footer";
const Home = () => {
return (
<div className="page-container">
<Header />
<Body />
<Footer />
</div>
);
}
export default Home;
header.js
import React from 'react';
import HeaderMenu from "./HeaderMenu";
const Header = () => {
return <>
<header className="header-area header-sticky wow slideInDown" data-wow-duration="0.75s" data-wow-delay="0s">
<div className="container">
<div className="row">
<div className="col-12">
<nav className="main-nav">
<HeaderMenu />
</nav>
</div>
</div>
</div>
</header>
</>
}
HeaderMenu.js
import React from "react";
import { Routes, Route, Link } from "react-router-dom";
import Login from './Login';
const HeaderMenu = () => {
return (
<>
<ul className="nav">
<li className="scroll-to-section"><a href="#top" className="active" >Home</a></li>
<li className="scroll-to-section">About Us</li>
<li className="scroll-to-section">Services</li>
<li className=""><Link to={"/Login"}>Login</Link></li>
<li className="scroll-to-section"><div className="main-red-button">Contact Now</div></li>
</ul>
</>
)
}
export default HeaderMenu;
Login.js
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
const Login = () => {
return (
<div>
<h1> Login Page </h1>
</div>
);
};
export default Login;
You have to define routes. Like on which route, which component has to be render. For example: for "/login" you want to define a route in "app.js" file. Like below:
import "./App.css";
import Home from "./components/Home";
import { BrowserRouter, Routes, Route } from "react-router-dom";
// import all page components like following
// import Login from "./components/Login";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
</Routes>
</BrowserRouter>
);
}
export default App;
I can't figure out why I cannot pass state from component ArrayList to ArrayList2. Can anyone chime in and offer a solution to the problem. I think I've exhausted every SO thread, YouTube video and Google search on the subject and I keep getting the following error message,
"Uncaught TypeError: Cannot destructure property 'message' of 'location.state' as it is null.".
My code is as follows:
Component 1
import "./App.css";
import ArrayList from "./ArrayList";
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
import ArrayList2 from "./dataFolder/ArrayList2";
function App() {
return (
<Router>
<Routes>
<Route exact path="*" element={<ArrayList />} />
<Route exact path="/2" element={<ArrayList2 />} />
</Routes>
</Router>
);
}
export default App;
Component 2
import { Link } from "react-router-dom";
import "./App.css";
import Years from "./dataFolder/Years";
import NavBar from "./NavBar";
function ArrayList() {
const years = Years;
return (
<div className="App">
<NavBar />
<nav>
<ul className="no-bullets">
{years.map((item) => (
<Link
className="no-link-style"
to={{
pathname: "/2",
state: { message: "This is a passed Item" },
}}
>
<li>{item}</li>
</Link>
))}
</ul>
</nav>
</div>
);
}
export default ArrayList;
Component 3
import React, { useState } from "react";
import { useLocation } from "react-router-dom";
import ArrayList from "../ArrayList";
import NavBar from "../NavBar";
function ArrayList2(props) {
const types = ["General", "Primary"];
const location = useLocation();
const { message } = props.location.state;
console.log(message)
return (
<div className="App">
<NavBar />
<ul className="no-bullets">
{types.map((item) => (
<li>{item}</li>
))}
</ul>
</div>
);
}
export default ArrayList2;
Any help on this would be greatly appreciated.
As I can see from the first code block, you are not passing any prop to ArrayList component, you are passing it to Link prop. Without passing a prop to the ArrayList component you are trying to access it. This leads to destructuring of an undefined value. You can use the passed route parameters by using the useParams hook that is defined in the react-router package.
After several attempts, I have managed to implement basic nested-routing with React-router-dom.
Here's the simple project structure:
Here are the relevant files:
App.js
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import ParentComponent from "./Components/nestedComponents/ParentComponent";
import NavBar from "./Components/Shared/NavBar";
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<Switch>
<Route path="/home" name="Home" component={ParentComponent} />
</Switch>
</BrowserRouter>
</div>
);
}
export default App;
NavBar.js
import React from "react";
import { Link } from "react-router-dom";
export default function NavBar() {
return (
<div>
<Link to={`home/nestedComponentOne`}> Nested Component One </Link>
<Link to={`home/nestedComponentTwo`}> Nested Component Two </Link>
</div>
);
}
ParentComponent.js
import React from "react";
import nestedComponentOne from "./nestedComponentOne";
import nestedComponentTwo from "./nestedComponentTwo";
import { Switch, Route } from "react-router-dom";
export default function ParentComponent() {
return (
<div>
<Switch>
<Route path="/home/nestedComponentOne" component={nestedComponentOne} />
<Route path="/home/nestedComponentTwo" component={nestedComponentTwo} />
</Switch>
</div>
);
}
nestedComponentOne.js
import React from "react";
export default function nestedComponentOne() {
return <div>NESTED COMPONENT 1</div>;
}
nestedComponentTwo.js
import React from "react";
export default function nestedComponentTwo() {
return <div>NESTED COMPONENT 2</div>;
}
So here's the Result:
If I click on nestedComponentOne:
If I click on nestedComponentTwo:
The problem is when I click again on nestedComponentOne (or Two) after the I have clicked it the first time, the route gets added to the url string instead of replacing it:
Some update need for your code.
Working Demo
NavBar.js
Here you forget to add slash / at front to link from root.
<Link to={`/home/nestedComponentOne`}> Nested Component One </Link>
<Link to={`/home/nestedComponentTwo`}> Nested Component Two </Link>
ParentComponent.js
As we removed the Switch from this component, so we need to get the matching information from parent router and pass the path to navigate the corresponding your nested component
export default function ParentComponent({ match }) {
return (
<div>
<Route path={`${match.path}/nestedComponentOne`} component={nestedComponentOne} />
<Route path={`${match.path}/nestedComponentTwo`} component={nestedComponentTwo} />
</div>
);
}
Why don't you try putting all the route in one file. Something like this:
<Route exact path="/home" name="Home" component={ParentComponent} />
<Route path="/home/nestedComponentOne" component={nestedComponentOne} />
<Route path="/home/nestedComponentTwo" component={nestedComponentTwo} />
I'm using React Router 4 in a TypeScript app where I have a React.Component that's used within a React.FunctionalComponent. I need to be able to navigate programmatically to a particular route from within the React.Component, but I can't seem to figure out how to pass the router down to the child component so that I can call this.props.history.push(). What complicates matters is that I'm using TypeScript, too.
Here's a code sandbox with a working demo of my component layout: https://codesandbox.io/s/react-programmatic-routing-xebpg
And now, the components:
app.tsx:
import * as React from 'react';
import { HashRouter } from 'react-router-dom';
import Header from './header';
import Footer from './footer';
import AppRouter from './app-router';
export default class App extends React.PureComponent {
public render() {
return (
<HashRouter>
<Header />
<AppRouter />
<Footer />
</HashRouter>
);
}
}
header.tsx:
import * as React from 'react';
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import { NavLink } from 'react-router-dom';
export default class Header extends React.PureComponent<any> {
public render() {
return (
<Navbar>
<Nav.Link as={NavLink} exact to="/home">
Home
</Nav.Link>{' '}
<Nav.Link as={NavLink} to="/customers">
Customers
</Nav.Link>
</Navbar>
);
}
}
app-router.tsx:
import * as React from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from './pages/home';
import Customers from './pages/customers';
const AppRouter: React.FC = () => {
return (
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/home" component={Home} />
<Route path="/customers" component={Customers} />
</Switch>
</div>
);
};
export default AppRouter;
pages/customers.tsx:
import * as React from 'react';
import MyFakeGrid from './customers-grid';
const Customers: React.FC = () => {
return (
<div>
<p>This is the customers page</p>
<MyFakeGrid />
</div>
);
};
export default Customers;
pages/customers-grid.tsx:
import * as React from 'react';
import { NavLink } from 'react-router-dom';
export default class MyFakeGrid extends React.Component {
public render() {
return (
<div style={{ borderColor: 'lightgray', borderStyle: 'solid' }}>
<p>
I need to be able to route programmatically from this
component
</p>
<p>
but I can't just use a NavLink like 'Home' (below), I have
to be able to navigate from within a method
</p>
<NavLink to="/home">Home</NavLink>
</div>
);
}
}
pages/home.tsx:
import * as React from 'react';
const Home: React.FC = () => {
return (
<div>
<p>This is the home page</p>
</div>
);
};
export default Home;
I've recently started learning React and I don't want to re-write my class-based components as functional components, which have become quite detailed/useful, especially not given React's gradual adoption strategy.
Base on React-router training, You can get access to the history object's properties and the closest 's match via the withRouter higher-order component. withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.
For example, you can re-write Customer component as blow:
import * as React from 'react';
import MyFakeGrid from './customers-grid';
import { withRouter } from "react-router";
const Customers: React.FC = () => {
return (
<div>
<p>This is the customers page</p>
<MyFakeGrid />
</div>
);
};
export default withRouter(Customers);
now you access to the history and other parameter as i said, and you can easily navigate between routes.
I have a homepage with a link to a form, like this:
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Route,
NavLink,
Redirect,
Switch,
withRouter
} from "react-router-dom";
import addHand from './Forms/addHand'
export class Home extends Component {
render() {
return (
<div>
<Router>
<div>
<NavLink to= '/hands/new'> Add a new hand </NavLink>
<Route path= '/hands/new' component={addHand}/>
<h4> Search For Hands By Category </h4>
<h4> Search For Sessions By Category </h4>
<h4> Search For Tables By Category </h4>
</div>
</Router>
</div>
);
}
}
export default Home;
I also have a navbar with a link to go home from any page, like this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import unmountComponentAtNode from 'react-dom';
class NavBar extends Component {
render() {
return (
<div className="navbar">
<NavLink className="link"
to="/"
exact
>Home</NavLink>
</div>
);
}
};
export default NavBar;
If I go to the form, then change my mind and decide I want to go back to the homepage, the url changes when I press the navlink, but the form is still rendered on the homepage. I can keep going back and forth between routes, but the only way to get the form to unmount from the DOM is to refresh the page. What causes this behavior, and what can I do to fix it? I have experienced similar issues before in React but have never found the solution. Thanks!
Edit** I tried adding this to the navlink:
render() {
const refCallback = node => {
unmountComponentAtNode(node)
}
return (
<div className="navbar">
<NavLink className="link"
to="/"
exact
innerRef={refCallback}
>Home</NavLink>
</div>
);
}
};
as per the react router docs, but it gives me this error:
unmountComponentAtNode(...): Target container is not a DOM element.
Here is the code in app.js
import React, { Component } from 'react';
import './App.css';
import { Router, Route } from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import Home from './Components/Home'
import Navbar from './Components/Navbar';
import addHand from './Components/Forms/addHand';
export const history = createBrowserHistory();
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title-top">Hi Adam, welcome to your Personal
Poker Universe!</h1>
<h1 className="App-title-middle">Not Adam? GTFO!</h1>
<h1 className="App-title-bottom">Just Kidding, you can stay</h1>
</header>
<Router history= {history}>
<div>
<Navbar/>
<Route exact path='/' component= {Home} />
</div>
</Router>
</div>
);
}
}
export default App;
Define one Router in your App.js:
<Router history={history}>
<Switch>
<Route exact path="/" component={Home} />} />
<Route path="/hands/new" component={addHand} />
</Switch>
</Router>
then try navigating between routes it should work. Please Let me know if it doesn't work