How routing with react-router-dom? - javascript

I installed react-router-dom and use this code for routing, But i have error :
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Switch } from 'react-router-dom';
class Home extends React.Component{
render(){
return(
<h1>Home</h1>
);
}
}
class About extends React.Component{
render(){
return(
<h1>About</h1>
);
}
}
ReactDOM.render(
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/about' component={About}/>
</Switch>,
document.getElementById('main')
);
What's the right way for routing in reactjs ?
tnx

Wrap BrowserRouter around your Switch like below,
<BrowserRouter>
<Switch>
<Route exact path='/' component={Home} />
<Route path='/about' component={About} />
</Switch>
</BrowserRouter>
Here is the working code demo in codesandbox.

You didn't import BrowserRouter
You should wrap your <Switch> arround <BrowserRouter> tag
Better use a component than trying to render a <Switch> element
You may find anything your looking for on this link :
https://reacttraining.com/react-router/web/guides/philosophy
Also i made a quick pen : https://codepen.io/FabienGreard/pen/KZgwKO?editors=1010

Kay Concepts
<BrowserRouter> is needed because
Each router creates a history object, which it uses to keep track of the current location and re-render the website whenever that changes
A React Router component that does not have a router as one of its ancestors will fail to work.
Router components only expect to receive a single child element. To work within this limitation, it is useful to create an component that renders the rest of your application.
<Route>
The component is the main building block of React Router. Anywhere that you want to only render content based on the location’s pathname, you should use a element.
<Path>
When the current location’s pathname is matched by the path, the route will render a React element.
<Switch>
You can use the component to group s.
The will iterate over its children elements (the routes) and only render the first one that matches the current pathname.
I think you should create different component for Routes.
I'll just explain general project structure here
You can create component to hold <Header> and <MainContent>
As <Header> will be same througout the application and it will not change if path changes. You can include routes in <MainContent> which will be updated if path changes.
MainContent.js
import { Switch, Route } from 'react-router-dom';
const MainContent = () => (
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/about' component={About}/>
</Switch>
</main>
)
export default MainContent;
Layout.js
class Layout extends Component {
render() {
return (
<div className={classes.root}>
<Header />
<MainContent />
</div>
);
}
Now you can use <BrowserRouter>to wrap your <Layout> in App.js . or you can use it in <MainContent> as well
App.js
import { BrowserRouter } from "react-router-dom";
class App extends Component {
render() {
return(
<BrowserRoter>
<Layout />
</BrowserRouter>
);
}
}

Related

React Router Dom v6 not working in my React page [duplicate]

This question already has an answer here:
Why I receive blank page? React
(1 answer)
Closed 6 months ago.
This is my app.js
I'm trying to preview the code but it's showing a blank page like extremely blank not even with an error while on my terminal it says compiled successfully!
import TopBar from './components/topbar/TopBar';
import Home from './pages/home/home';
import Write from './pages/write';
import Single from './pages/single';
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
function App() {
return (
<>
<Router>
<TopBar/>
<Routes>
<Route exact path ="/" element = {Home} />
<Route path ="/write" element = {Write} />
<Route path ="/single" element = {Single} />
</Routes>
</Router>
</>
);
}
export default App;
With React Router Dom v6 you should be calling the given component to element property, like so:
<Route exact path ="/" element = {<Home/>} />
<Route path ="/write" element = {<Write/>} />
<Route path ="/single" element = {<Single/>} />
Check your browser console to see more details.
but as far as i know in version 6 there is no exact in <Route/> props remove it
try removing exact and using child routers I think that would help
function App() {
return (
<>
<Router>
<TopBar />
<Routes>
<Route path="/" element={Home}>
<Route path="write" element={Write} />
<Route path="single" element={Single} />
</Route>
</Routes>
</Router>
</>
);
}

Reactjs screen is not rendering

I think that the problem is in the switch, in version of react-router-dom or in routes. Only when I created and applied the code in this class, the screen started don't render and stays white. I already changed the version of react-router-dom but I don't know what can be.
Below the code of routes.js:
//react-router-dom version: "^5.3.0"
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import Home from './pages/Home';
import Header from './components/Header';
const Routes = () => {
return(
<BrowserRouter>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
</Switch>
</BrowserRouter>
)
}
export default Routes;
React Router v6 introduces some changes like.
Routes component that is kind of like Switch, but a lot more powerful one.
Route still exist but you don't pass a pointer to that component function or as a children component, Instead you pass the JSX element to the element prop &
exact doesn't exist anymore, now it's always looks for exact matches.
So, component={Home} would become element={<Home />}
Something like this
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />} />
</Routes>
You can dive deep to this migration guide: https://reactrouter.com/docs/en/v6/upgrading/v5
hope that's help you

Not able to use WithRouter of react-router-dom

I am new to the react js. Here I am trying to use the withrouter to get the info of my location.
SO, I have following structure.
index.js
ReactDOM.render(
<App />
, document.getElementById('root'));
App.js
<Provider store={store}>
<div>
<Header />
<Main />
</div>
</Provider>
Main.js
return (
<Router history={history}>
<div>
{this.props.isFetching && <Loading />}
<Switch>
<PrivateRoute exact path="/" component={LandingPage} />
<PrivateRoute exact path="/create-job" component={NewJob} />
<PrivateRoute exact path="/user-jobs" component={JobList} />
<Route exact path="/login" component={Login} />
</Switch>
</div>
</Router>
Now, I am trying to use the withRouter in the Header.js. which is not a part of the Router. SO,
import { withRouter } from "react-router-dom";
export default withRouter(connect(mapStateToProps, { logout })(Header));
I tried using this way. So, it is giving me the following error.
You should not use <Route> or withRouter() outside a <Router>
What is it that I am doing wrong over here ?
You're rendering the Header component (which uses withRouter) outside the Router component. You need to make sure that all the Routes and the components using withRouter need to be a child of Router, at some level in the hierarchy.
In your case, maybe wrap the div in the App with the Router?
Details from source
The error is generated here when Route doesn't get passed a context from its provider. And, withRouter is just a wrapper over Route. The only time the context is not available is when the Route is not nested inside a Router somewhere.
Your issue is that withRouter props get blocked by PureComponent check, put it after connect:
export default connect(mapStateToProps, { logout })(withRouter(Header));
See: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/withRouter.md#important-note
Personally I prefer to have my providers in one place in index.js not App.js, your whole app should be wrapped in Router, not a part of App.js:
const WrappedApp = (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
);
ReactDOM.render(WrappedApp, document.getElementById('root'));
You need to move <Header> component inside <Router> component, otherwise it doesn't work as the error says.
So you want to do 2 things, inject the state in the Header, and inject routing information in Header.
If you are outside of the <Router/> component you will not be able to use withRouter(, simply because you will not have any match props to link to your compoonent.
What you need to do is to create something called layouts.... and use the layouts in the page definition like this.
Lets say you have this Route <PrivateRoute exact path="/" component={LandingPageContainer} />
Now inside the LandingPage you need to do something like
landingPageContainer.js
render() {
return (
<SimpleLayout header={<Header ...this.props/> footer={<Footer ...this.props/>}>
<LandingPageDummyPage ...this.props/>
<SimpleLayout/>
);
}
export default connect(withRouter(LandingPageContainer);
this will copy all the props passed to the Simple Layout to your LandingPageLayout, header and footer
simpleLayout.js
render() {
return (
<div>{this.props.header} </div>
<div>{this.props.children} </div>
<div{this.props.footer} </div>
);
}
export withRouter(SimpleLayout);
advice . read the router documentation and try to understand whats the purpose if it... you didn`t quite get it :) ...

React Router v4 Multiple Dynamic Routes

I'm new to React Router so if this has been asked before maybe someone could point me in the right direction! Basically I have a WordPress install that I'm pulling in my websites data from through the API.
I've created custom routes to query my pages and my posts by slug.
Using react router I was able to create a template called Page.js which changes dynamically using the code below.
However, now I'm trying to do the same exact thing with the blog posts but the app isn't using Blog.js its still defaulting back to Page.js
here's my App.js code...
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from './pages/Home';
import Page from './pages/Page';
import Blog from './pages/Blog';
import Header from './components/Header';
import Footer from './components/Footer';
class App extends React.Component {
render() {
return (
<Router>
<div>
<Header/>
<Route exact path="/" component={Home} />
<Route path="/:slug" component={Page} />
<Route path="/blog/:slug" component={Blog} />
<Footer/>
</div>
</Router>
);
}
}
export default App;
More Details:
Page.js works by checking const { slug } = this.props.match.params; and then querying WordPress using that slug to pull in the data it needs. In componentDidUpdate i'm checking prevProps to see if the slug matches the previous slug, if not it fetching the new data.
This works great and I was hoping to do the same in the Blog.js as well.
However, if this isn't the best approach please advise another method.
Two things:
Use element: This will allow only one route to be used, no composing. (See this documentation)
Check the order of path statements: Use defined paths before :param, this avoids considering /blog/:slug as a /:slug parameter.
`
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
class App extends React.Component {
render() {
return (
<Router>
<div>
<Header/>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/blog/:slug" component={Blog} />
<Route path="/:slug" component={Page} />
</Switch>
<Footer/>
</div>
</Router>
);
}
}
I think you're pretty close to the recommended implementation, just a few small tweaks should get you there.
First,
In your App.js file you're actually handling routing, without using the <Switch> component provided by React Router, replacing the <div> and </div> tags in your App.js file with <Switch> and </Switch> respectively should get this working for you. See below...
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; //make sure you import it also!
import Home from './pages/Home';
import Page from './pages/Page';
import Blog from './pages/Blog';
import Header from './components/Header';
import Footer from './components/Footer';
class App extends React.Component {
render() {
return (
<Router>
<Switch> //Add this in
<Header />
<Route exact path="/" component={Home} />
<Route path="/blog/:slug" component={Blog} />
<Route path="/:slug" component={Page} />
<Footer />
</Switch> //Add this in
</Router>
);
}
}
export default App;
I would recommend going further though!
To make these components more understandable, you should refactor routing functionality into a routes.js file, and top-level App component logic/structure into the App.js file. See below...
In App.js:
This file is where you should handle your base application structure and logic. For example this file is where you'll import your <Header>, your <Footer>, and where the Route component will render.
import * as React from 'react'
import Header from './../Header/Header.jsx'
import Footer from './../Footer/Footer.jsx'
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
// Handle your top-level application state here
}
}
// define your top-level application functions here
render() {
return (
<div>
<Header />
<main>
{this.props.children} //This where the Route components will render
</main>
<Footer />
</div>
)
}
}
export default App
In Routes.js:
This file is where you should import your App component, and then handle the routing statements.
import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import App from './components/App'
import Home from './pages/Home'
import Page from './pages/Page'
import Blog from './pages/Blog'
/* construct routes */
export default () => {
return (
<Router>
<App>
<Switch>
<Route path='/' exact component={Home} />
<Route path='/blog/:slug' component={Blog} />
<Route path='/:slug' component={Page} />
</Switch>
</App>
</Router>
)
}
If you structure your application this way, your routing logic and top-level application logic are separate, and in the end your files will be less cluttered as both Route files and top-level App files can get fairly dense.
Hope this helps! Let me know if I can explain anything further.

BrowserRouter from react-router-dom doesn't render components

I tried to move BrowserRouter out of my component. My App looked like this:
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<BrowserRouter>
<main>
<Menu />
<Switch>
<Route exact path="/about" component = {About} />
<Route exact path="/admin" component = {BooksForm} />
<Route exact path="/cart" component = {Cart} />
<Route exact path="/" component = {BookList} />
</Switch>
<Footer />
</main>
</BrowserRouter>
);
}
}
And everything was working fine. But when I pulled BrowserRouter up, so my index.js would look like this:
const renderApp = () => (
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>
)
const root = document.getElementById('app')
render(renderApp(), root)
it stopped working. When I click on one of the links the url changes but there's no change in my app. It renders new componennt only if I reload the page. How can I make it work without placing router component in the same component as Switch?
Tough to tell without looking at the rest of the code. Are you using the proper react-router <Link>s? I assume you don't have the <BrowserRouter> element in both components, can't imagine that nesting them would do any good.
I'm on an old version of react-router, so I'm seeing some of these examples for the first time, but it looks like you don't need the exact keyword on all of those <Route>s within <Switch> -- the switch guarantees that only one of them will math.
Allright I've made it working again. Connect from redux was causing the problem and withRouter solved it

Categories