React router v4 render component inside element - javascript

I'm using the latest version of React Router v4 and I'm trying to render my page components Home/About inside the PageWrap div but the problem I'm having is that if I add the Routes into my header then it will switch the routes but they will display the Home/About component as part of the header and no where I want them to be.
If I put the routes into the PageWrap then the router doesn't work but doesn't throw any errors on the console.
How can I display and switch between components in the PageBody div?
Webpack link
app.js
import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import styled from 'styled-components'
import Header from './Header'
import Home from './pages/Home'
import About from './pages/About'
const Wrapper = styled.div`
display:flex;
min-height:100vh;
flex:1;
background:#eee;
`
const PageWrap = styled.div`
margin:0 auto;
min-width:1400px;
background: #000;
`
class App extends React.Component { // eslint-disable-line react/prefer-
stateless-function
render() {
return (
<div>
<Header />
<Wrapper>
<PageWrap>
<Router>
<Switch>
<Route exact path="/login" component={Home} />
<Route exact path="/frontpage" component={About} />
<Route exact path="/logout" render={() => (<div>logout</div>)} />
</Switch>
</Router>
</PageWrap>
</Wrapper>
</div>
)
}
}
export default App
Header.js
import React from 'react'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
import styled from 'styled-components'
import Home from '../pages/Home'
import About from '../pages/About'
import Topics from '../pages/Topics'
const Wrapper = styled.div`
width:100%;
height:100px;
background:papayawhip;
`
class Header extends React.Component { // eslint-disable-line react/prefer-
stateless-function
render() {
return (
<Router>
<Wrapper>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route path="/topics" component={Topics} />
</Wrapper>
</Router>
)
}
}
export default Header
home.js
const Home = () => (<div>Home</div>)
About.js
const About = () => (<div>About</div>)

You should only have one <Router> in your application and it should wrap all your <Route /> and <Link/> components in your component tree.
So your render method in App component should be something like this.
render() {
return (
<Router>
<div>
<Header />
<Wrapper>
<PageWrap>
<Switch>
<Route exact path="/login" component={Home} />
<Route exact path="/frontpage" component={About} />
<Route exact path="/logout" render={() => (<div>logout</div>)} />
</Switch>
</PageWrap>
</Wrapper>
</div>
</Router>)
}
And make sure to remove <Router> and all <Route>s from your Header component.
Updated WebpackBin:https://www.webpackbin.com/bins/-KiLrUNoJVxxLhL8UWx1

At some point, when you have "tens or hundreds" or routes you may want to delegate routing.
You can see that referred to here as child routing

Related

react-router-dom's Route do not work in my project

I'm in the very first step to create an project, but the react-router-dom's 'Route' just don't work. When i try to use it, just erase all other things in the screen.
My app.js:
import { BrowserRouter, Route } from 'react-router-dom';
import './App.css';
import Header from './components/Header';
import CoinPage from './Pages/CoinPage';
import Homepage from './Pages/Homepage';
function App() {
return (
<BrowserRouter>
<div>
<Header />
<Route path="/" component={Homepage} />
<Route path="/coins/:id" component={CoinPage} />
</div>
</BrowserRouter>
);
}
export default App;
My CoinPage.js:
import React from 'react'
const CoinPage = () => {
return (
<div>
Coin Page
</div>
)
}
export default CoinPage
My Homepage.js:
import React from 'react'
export const Homepage = () => {
return (
<div>
Homepage
</div>
)
}
export default Homepage
My Header.js:
import React from 'react'
/*The header it self:*/
export const Header = () => {
return (
<div>
Header
</div>
)
}
export default Header
When I remove <Route path="/" component={Homepage}/> and <Route path="/coins/:id" component={CoinPage} /> the 'Header' component appears again
You need to wrap all your Route inside Routes Component
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
<BrowserRouter>
<div>
<Header />
<Routes>
<Route path="/" component={Homepage} />
<Route path="/coins/:id" component={CoinPage} />
</Routes>
</div>
</BrowserRouter>
If you are using v6, then component has been replaced by element in Route
<Route path="/" element={<Homepage />} />
<Route path="/coins/:id" element={<CoinPage />} />
Solved!
I needed to change component to element and put each Route in a different Routes tag. Like that:
<BrowserRouter>
<div>
<Header />
<Routes>
<Route path="/" element={<Homepage />} />
</Routes>
<Routes>
<Route path="/coins/:id" element={<Coinpage />} />
</Routes>
</div>
</BrowserRouter>

Nothing appears while using react router

I have a problem with react Router.
So i am building the nav of an website and when i'm doing the routes, nothing appears.
Would you help me please to see what i'm doing wrong?
The page stays white. Nothing appears, even the root doesnt see the homepage.
........................................................................................
Homepage:
import React from 'react';
import Navbar from '../allpages/navbar/Navbar';
import {
BrowserRouter as Router, Routes, Route
} from "react-router-dom";
import Contact from "../contact/Contact";
import About from "../about/About";
const Home = () => {
return (
<>
<Router>
<Navbar />
<Routes>
<Route path="/about" element={About} />
<Route path="/contact" element={Contact} />
<Route exact path="/" element={Home} />
</Routes>
</Router>
<h3>Home</h3>
</>
)
}
export default Home
Navbar:
import React from 'react';
import {
BrowserRouter as Link
} from "react-router-dom";
const Navbar = () => {
return (
<div>
<nav>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
</ul>
</nav>
</div>
)
}
export default Navbar
main app:
import './App.css';
import Home from './components/home/Home'
function App() {
return (
<>
<Home />
</>
);
}
export default App;
contact:
import React from 'react';
const Contact = () => {
return (
<div>
<h3>Contact</h3>
</div>
)
}
export default Contact
About:
import React from 'react';
const About = () => {
return (
<div>
<h1>About</h1>
</div>
)
}
export default About
So besides this typo:
{ BrowserRouter as Link } // use just Link
which is inside Navbar.js
I would also use recommended approach by React-Router team. Which uses <Switch> component to wrap pages. You are using Routes instead, idk if this is even valid.
You can check this example: https://v5.reactrouter.com/web/example/basic
which is really similar to your code.
What versión is you using? You might be out of dated
<React.Suspense fallback={<p>Loading...</p>}>
<Routes>
<Route path="/*" element={<Outlet />}>
<Route path="informacion-financiera" element={<Financiera />} />
<Route path="derechos-de-autor" element={<Author />} />
<Route
</Route>
</Routes>
</React.Suspense>
```
What versión is you using? You might be out of dated
<React.Suspense fallback={<p>Loading...</p>}>
<Routes>
<Route path="/*" element={<Outlet />}>
<Route path="informacion-financiera" element={<Financiera />} />
<Route path="derechos-de-autor" element={<Author />} />
<Route
</Route>
</Routes>
</React.Suspense>
```
You have browserRouter as Link so yow links are not links

Functions are not valid as a React child when wraping Routes in App

I'm trying to wrap Routes using Layout component so it puts all content into a bootstrap 12 column grid.But it doesnt wrap my text inside Route components and I get a warning that functions are not valid as a React child. Here is the App.js code:
import './App.css';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Home from './Home';
import Offers from './Offers';
import Financing from './Financing';
import Buying from './Buying';
import Contact from './Contact';
import Gallery from './Gallery';
import Search from './Search';
import Layout from './components/Layout';
function App() {
return (
<Fragment>
<Layout>
<Router>
<Routes>
<Route path='/' element={Home} />
<Route path='/fahrzeugangebote/' element={Offers} />
<Route path='/finanzierung/' element={Financing} />
<Route path='/fahrzeugankauf/' element={Buying} />
<Route path='/galerie/' element={Gallery} />
<Route path='/kontakt/' element={Contact} />
<Route element={Search} />
</Routes>
</Router>
</Layout>
</Fragment>
);
}
export default App;
And here is the code for Layout.js:
import Container from 'react-bootstrap/Container';
export const Layout = (props) => {
return(
<Container>
{props.children}
</Container>
)
};
export default Layout ```
As you can see in the docs, you have to provide the elements like this (ReactElement):
<Route path='/' element={<Home />} />
<Route path='/fahrzeugangebote/' element={<Offers />} />
// etc

React Router v4 nested routes props.children

I'm updating my universal react redux app to use react router v4. I have nested routes under a main layout route. Previously I used {props.children} to show contents of child routes, but this doesn't work anymore. How does this work in V4?
<Provider store={store} key="provider">
<div>
<Route component={Layout} />
<Switch>
<Route path="/" component={HomePage} />
<Route component={Error404} />
</Switch>
</div>
</Provider>
or
<Provider store={store} key="provider">
<Layout>
<Route path="/" component={HomePage} />
<Route component={Error404} />
</Layout>
</Provider>
This is how my Layout file looks
const Layout = props => (
<div className="o-container">
<Header />
<main>
{props.children}
</main>
<Footer />
</div>
);
I have taken the <Provider>out because it belongs to react-redux and you don't need it as basis for routing with react-router (anyway you can easily add it encapsulating the structure with it).
In React Router V4, what was Router has been renamed to BrowserRouter and imported from package react-router-dom. So for nesting routes you need to insert this as children of your <Layout>.
index.js
import { Switch, Route } from 'react-router';
import { BrowserRouter } from 'react-router-dom';
import Layout from './Layout';
...
const Root = () => (
<Layout>
<BrowserRouter>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/other" component={OtherComponent} />
<Route component={Error404} />
</Switch>
</BrowserRouter>
</Layout>
);
ReactDOM.render(
<Root/>,
document.getElementById('root')
);
Layout.js
import React from 'react';
import Header from './Header';
import Footer from './Footer';
const Layout = props => ({
render() {
return (
<div className="o-container">
<Header />
<main>{props.children}</main>
<Footer />
</div>
);
}
});
export default Layout;
Take in count this only works for web. Native implementation differs.
I uploaded a small project based in Create React App where I show the implementation of nested routes in V4.
Just thought I have to share this. If you're using a Link component in your Header component. The answer above won't work. You would have to make the BrowserRouter as the parent again to support Link. Make it like this:
<BrowserRouter>
<Layout>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/other" component={OtherComponent} />
<Route component={Error404} />
</Switch>
</Layout>
</BrowserRouter>
I would use this structure, without props.children :
const Main = () => (
<main>
<Switch>
<Route exact path="/" component={HomePage} />
<Route component={Error404} />
</Switch>
</main>
)
const Layout = () => (
<div>
<Header />
<Main />
<Footer />
</div>
)
ReactDOM.render((
<Provider store={store}>
<BrowserRouter>
<Layout />
</BrowserRouter>
</Provider>
), document.getElementById('root'))
Please read this blog through. https://codeburst.io/react-router-v4-unofficial-migration-guide-5a370b8905a
No More <IndexRoute>
The component allowed to route to a certain component on a top-level path in v3:
// in src/MyApp.js
const MyApp = () => (
<Router history={history}>
<Route path="/" component={Layout}>
<IndexRoute component={Dashboard} />
<Route path="/foo" component={Foo} />
<Route path="/bar" component={Bar} />
</Route>
</Router>
)
This component doesn’t exist anymore in v4. To replace it, use a combination of , exact, and route ordering (placing the index route last):
// in src/MyApp.js
const MyApp = () => {
<Router history={history}>
<Route path="/" component={Layout} />
</Router>
}
// in src/Layout.js
const Layout = () => (
<div className="body">
<h1 className="title">MyApp</h1>
<div className="content">
<Switch>
<Route exact path="/foo" component={Foo} />
<Route exact path="/bar" component={Bar} />
<Route exact path="/" component={Dashboard} />
</Switch>
</div>
</div>
);
Adding to #Dez answer
Complete native / core implementation with Redux support
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, Switch } from 'react-router';
import createMemoryHistory from 'history/createMemoryHistory';
const history = createMemoryHistory();
import App from './components/App';
import Home from './components/Home';
import Login from './components/Login';
import store from './store';
ReactDOM.render((
<Provider store={ store }>
<Router history={history}>
<App>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
</Switch>
</App>
</Router>
</Provider>
), document.getElementById('root'));
App.js
import Header from './Header';
import Home from './Home';
import React from 'react';
import {connect} from 'react-redux';
const mapStateToProps = state => ({appName: state.appName});
class App extends React.Component {
render() {
return (
<div >
<Header appName={this.props.appName} /> {/*common header*/}
{this.props.children}
</div>
);
}
}
export default connect(mapStateToProps, () => ({}))(App);
If using with Redux, without the Switch element
AppRouter.js
import React from 'react'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
const AppRouter = () => (
<Layout>
<Router>
<div>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/contact" component={Contact}/>
</div>
</Router>
</Layout>
)
export default AppRouter;
Layout.js
const Layout = props => ({
render() {
return (
<div className="container">
<Header />
<main>{props.children}</main>
<Footer />
</div>
);
}
});
export default Layout;
Provider placed in Render function
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import AppRouter from './AppRouter';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<AppRouter />
</Provider>
, document.getElementById('app'));

React router global header

I just started learning React, I'm trying to make a SPA blog, which has a global positioned fixed header.
import React from 'react';
import { render } from 'react-dom';
// import other components here
render((
<Router history={browserHistory}>
<Route path="/" component={Home} />
<Route path="/About" component={About} />
<Route path="/Contact" component={Contact} />
<Route path="*" component={Error} />
</Router>
), document.getElementById('app'));
So, each routes has the same header and from my angular background, I would use header outside ui-view.
Its a good practice to import the header component in each individual page component, or can I add the header component on my <Router><myHeader/><otherRoutes/></Router>?
Update:
I was thinking to use something like this:
Routes component, where I define my routes:
class Routes extends React.Component {
render() {
return (
<Router history={browserHistory}>
<IndexRoute component={Home} />
<Route path="/studio" component={Studio} />
<Route path="/work" component={Work} />
<Route path="*" component={Home} />
</Router>
)
}
}
And then on main Index.js file I would like to render something like:
import Routes from './components/Routes';
render((
<div>
<div className="header">header</div>
<Routes />
</div>
), document.getElementById('app'));
Can someone explain me? Thanks!
From my experience it can be good to define a layout component for your page, something like...
Layout Component
render() {
return(
<div>
<Header />
{ this.props.children }
/* anything else you want to appear on every page that uses this layout */
<Footer />
</div>
);
}
You then import layout into each of your page components...
Contact Page Component
render() {
return (
<Layout>
<ContactComponent />
/* put all you want on this page within the layout component */
</Layout>
);
}
And you can leave your routing the same, your route will render the contact page and in turn will render your header.
This way you get control of repetitive stuff that will be on multiple pages, if you need one or two slightly different pages you can just create another layout and use that.
I find this way useful:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Header from "./components/Header";
import Home from "./components/Home";
import Dashboard from "./components/Dashboard";
import Footer from "./components/Footer";
class App extends Component {
constructor() {
super();
this.state = {
stuff: stuff;
};
}
render() {
let { stuff } = this.state;
return (
<Router> //wrapper for your router, given alias from BrowserRouter
<div className="App">
<Header /> //this component will always be visible because it is outside of a specific Route
<Route exact path="/" component={Home}/> //at the root path, show this component
<Route path="/dashboard" component={()=><Dashboard stuff={stuff} />}/> //at the path '/dashboard', show this other component
<Footer /> //this is also permanently mounted
</div>
</Router>
);
}
}
export default App;
credit goes to: David Kerr
The question is already answered but I'm here to show another approach and say why I prefer that.
I also think that it's a good thing to have a Layout component
function Layout (props) {
return (
<div>
<Header/>
<div className="content">
{props.children}
</div>
</div>
);
}
But instead of render it into each route component you can render it just once as a parent for your routes.
return (
<Router>
<Layout>
<Switch>
<Route path="/about">
<About/>
</Route>
<Route path="/contact">
<Contact/>
</Route>
<Route path="/">
<Home/>
</Route>
</Switch>
</Layout>
</Router>
);
This is good because in most cases you will not waste time with the layout and if you have different layouts you only need to work inside the Layout component.
For forcefully refresh Header inside routing. use forceRefresh={true}
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}
I've another solution that is make the routing like this
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}
and in the header file edit as this
import React, {useLocation} from "react";
const header = () => {
const location = useLocation();
return(
<div className={location.pathname === 'login' ? 'd-none': 'd-block'}>
abc
</div>
)
}
export default header;
this will hide the header panel in login page.

Categories