Routes unable to load using react-router - javascript

I'm designing a simple application using create-react-app and I've recently delved into the power of react-router. However, I'm having an issue with pages getting stuck trying to load, and I'm not sure why.
I've got a Navbar component, for which I'll condense the gist of what it is.
import React from 'react';
import { BrowserRouter as Router, Link, Switch, Route } from 'react-router-dom';
import BlogPost from '../Pages/BlogPost';
// Condensed because a lot of the detail is unnecessary and no-one likes blocks of unneeded code
class Navbar extends React.Component {
render() {
return (
<Router>
<nav>
<div id="navigationlinks">
<ul id="navlinks-left">
<li className="nav-item"><Link to='/'>Home</Link></li>
<li className="nav-item"><Link to='/about'>About</Link></li>
</ul>
</div>
</nav>
<Switch>
<Route path='/post' component={BlogPost} />
<Route path='/about'>
<About />
</Route>
</Switch>
</Router>
);
}
}
function About() {
return <h2>The about page.</h2>;
}
export default Navbar;
BlogPost represents a component that is a page in itself. The code looks like this. Again, I'll abstract away from the stuff that's not relevant.
import React from 'react';
import Navbar from '../Components/Navbar';
// Other components on this page. None of them reference the navbar or contain a router of their own.
import BlogBox from '../Sections/BlogBox';
import CommentForm from '../Components/CommentForm';
import CommentBox from '../Sections/CommentBox';
class BlogPost extends React.Component {
getBlogPost(address) {
// Gets blog data (like the title, description, content, image, etc.) using 'fetch' from
// an API at 'address'. Abstracted away because this isn't relevant.
}
componentDidMount() {
console.log("Blog post mounted!");
this.getBlogPost("http://localhost:8080/api/blog/samplepost");
}
render() {
return (
<div className="blog-post">
<Navbar />
<BlogBox post={this.state ? this.state.post : ""}/>
<CommentForm />
<CommentBox comments={this.state ? this.state.comments: ""} />
</div>
);
}
}
export default BlogPost;
The homepage of my application is located at '/'. It's rendered in my index.js file, the code of which is below.
import React from 'react';
import ReactDOM from 'react-dom';
import BlogHome from './Pages/BlogHome';
import BlogPost from './Pages/BlogPost';
ReactDOM.render(
<BlogHome />,
document.getElementById('root')
);
The homepage renders fine, but when I go to navigate to /post, the application attempts to load the page indefinitely, and eventually times out, being unable to do so.
Notice how the BlogPost page component renders the Navbar component, which in turn has a path /post which renders the BlogPost object? I'm not sure if I'm able to change this. Could this be the reason why the /post path can't load?
What concerns me the most here is that I eventually would like to add additional pages which will not only contain this same Navbar, but for which their page links also exist in this Navbar. For example, if I add an About page, this page will not only contain the Navbar, but its link will also be present in this Navbar!
Is there a way I can keep such self-page links in the Navbar, without the recursive render loop occurring?

Issue
You are creating a cycle between rendering Navbar and BlogPost when the current path matches "/post`.
In other words BlogHome renders a Navar which renders a BlogPost which then renders another Navbar and another BlogPost ad nauseam.
Solution
Restructure your navbar and routes a bit to split them out
index.js
Since BlogHome sounds like a page it should be placed on its own route. Move Router here to wrap entire app. Render BlogHome path last as that matches all path prefixes, so it will render if no other route is matched above it by the Switch.
ReactDOM.render(
<Router>
<Switch>
<Route path='/post' component={BlogPost} />
<Route path='/about'>
<About />
</Route>
<Route path="/" component={BlogHome} />
</Switch>
</Router>,
document.getElementById('root')
);
Navbar
Remove the router and routes, leave links only.
class Navbar extends React.Component {
render() {
return (
<nav>
<div id="navigationlinks">
<ul id="navlinks-left">
<li className="nav-item"><Link to='/'>Home</Link></li>
<li className="nav-item"><Link to='/about'>About</Link></li>
</ul>
</div>
</nav>
);
}
}
Now each page should be free to render a Navbar or not.

try to remove Navbar in your BlogPost component, because when the location changes it will switch component here
<Switch>
<Route path='/post' component={BlogPost} />
<Route path='/about'>
<About />
</Route>
</Switch>
and
<nav>
<div id="navigationlinks">
<ul id="navlinks-left">
<li className="nav-item"><Link to='/'>Home</Link></li>
<li className="nav-item"><Link to='/about'>About</Link></li>
</ul>
</div>
</nav>
will persisit.

Related

How to Navigate to sections with id as well as pages in React Router Dom?

I have a Main page that contains 4 section ** #home, #collection, #products and #contact** and I have 2 different page for /cart and /login
Navbar Code is Here
`<nav>
<div className='wrap-nav'>
<NavLink href="" className='logo'>NILESTORE</NavLink>
<div className='wrap-ul'>
<ul className='nav-links' >
<li><NavLink to="#home">Home</NavLink></li>
<li><NavLink to="#collection">Collection</NavLink></li>
<li><NavLink to="#products">Products</NavLink></li>
<li><NavLink to="#contact">Contact</NavLink></li>
</ul>
<ul className='nav-items'>
<li><NavLink to="/cart" className='cart' data-item={data.cartItems.length}><BsBag /></NavLink></li>
<li><NavLink to="/login" className='login'>Login</NavLink></li>
</ul>
</div>
</div>
</nav>`
App.js code is here
import React from 'react'
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import "./App.css"
import Navbar from './components/Navbar'
import Cart from './pages/Cart';
import Main from './pages/Main';
function App() {
return (
<>
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Main />} />
<Route path="/cart" element={<Cart />} />
</Routes>
</Router>
</>
)
}
export default App
SO when I am in main page that works fine and I can reach that section when clicking the section like when i click on products i can reach on #products
After that when I click on /cart and /login page I can reach on that page but myNavbar is same for all pages so when I click on Products, it doesn't work
I have tried all the possibilities on changing the NavLink like I have changed #products to /#products but also It doesn't work
Is there any solution for that
I think you can do one of these two:
First You can change your navbar and when you go to a page like a login page or cart page , your navbar doesn't show the other option till the user get back to the home page.
Second is that you pass a variable when you click on those (home, collection, products, and contact). you will say okay go to the home page if I am not at the home page then you will check the state and if there was one of these variables (home, collection, products, and contact) you can navigate to them by using js.
pathname: '/somewhere',
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
basically, this is what you find when you use location hook.
for more information check out the website
react-router-dom "#location"
To navigate to a particular section of a particular page, you might want to use a HashLink in your Navbar component.
Installation:
npm i react-router-hash-link
Import it as:
import { HashLink } from 'react-router-hash-link';
And use it as:
<li><HashLink to={"/page#id"}>Contacts</HashLink></li>
You can learn more about the same here
Hope this helps!

Using App component as a home page in react (path "/")

this is my first question here and I apologize upfront if it already been answered. I'm studying react and I started a project as well, and my question is: how can I make my App component a home page? Or do I have to create a component to do so? I´m using react-router-dom for navigation, like the code below, and keep getting the message "No routes matched location "/"". How can I set a route to it? I would like to use the App component instead of using a page component named home. If I did something wrong about the post, again, I'm sorry. Thanks in advance.
import React from 'react'
import {BrowserRouter as Router, Routes, Route, Link} from 'react-router-dom'
import Blog from './pages/Blog'
import About from './pages/About'
import Faq from './pages/Faq'
import Market from './pages/Market'
import GlobalStyle from './styles/global'
function App() {
return (
<Router>
<GlobalStyle/>
<header>
<nav>
<Link to="/products">Nosso produtos</Link>
<Link to="/blog">Diário do Café</Link>
<Link to="/faq">Cafaq - perguntas frequentes</Link>
<Link to="/about">Sobre nós</Link>
</nav>
</header>
<Routes>
<Route path="/products" element={<Market />} />
<Route path="/blog" element={<Blog />} />
<Route path="/faq" element={<Faq />} />
<Route path="/about" element={<About />} />
</Routes>
<footer> Footer </footer>
</Router>
)
}
export default App
The App component is already your default component. Any path will render the App component as long as you have wrapped the App component with the BrowserRouter component
// In index.js
import App from "./App";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
so I assume your point is to keep the navbar visible regardless of the current path and that is already done because anything placed in the App component will be rendered, and the paths content will be changed based on the elements specified in the Routes.
In case, you want to create a separate Home component, then you will create a Route with a path '/' and the Home Component element.
Make sure that you understand how routing works to avoid any bugs in the future
Hope you found it helpful.
The route element with path ="/" will be your home page
Try with this;
<Route path='/' exact element={<Home/>} />

React - Adding a tab to navbar that manipulates page data instead of invoking route redirect

I have a react App and I am using Browser router and a component named Navigation for navigation.
I want to know how to add a tab to the Nav that is not for navigation, but instead allows the user to manipulate a components JSX on a specific page.
I do not know how to structure this. I figure I could use the Context API (maybe?) but before I go down that rabbit hole I figure someone might know a different/better way.
Here is some dummy code
Nav.js
import React from "react";
function Navigation(props){
console.log(props)
return(
<ul>
<li>Landing</li>
<li>Test</li>
<button>Invoke some action on /test</button>
{/* If I am on a page named /test I want this button to have the abillity to trigger a function on that page*/}
</ul>
)
}
export default Navigation
App.js
import React from 'react';
import { BrowserRouter, Route, Redirect } from "react-router-dom";
import Navigation from "./Navigation";
import Test from "./Test";
import { withRouter } from "react-router";
import {Switch} from 'react-router';
import logo from './logo.svg';
import './App.css';
function App(props) {
return (
<div className="App">
<BrowserRouter>
<div>
<Navigation/>
<Switch>
<Route exact path="/test" component={Test} />
<Route exact path="/some-stuff" component={Whatever} />
<Route exact path="/some-more-stuff" component={WhateverElse} />
<Redirect from="/*" to="/test" />
</Switch>
</div>
</BrowserRouter>
</div>
);
}
export default withRouter(App);

React Router Changes URL, but BrowserRouter doesn't change Viewed Component

The project I am working on is kinda of sensitive, but here's what I have that I can show you all.
When I click on one of the s in my NavBar, it changes the URL, but it does not change the view to the proper component. Does anyone have any idea why? If there's a better way I can phrase this or improve the quality of my questin, let me know.
My render that I return
<NavBar />
<BrowserRouter>
<div>
<Switch>
<Route path="/propertytypes" component={PropertyTypes} />
<Route path="/entitytypes" component={EntityTypes} />
<Route path="/associationtypes" component={AssociationTypes} />
<Route path={Routes.ROOT} component={Test} />
</Switch>
</div>
</BrowserRouter>
My NavBar
import React, { Component } from "react";
import { Link } from "react-router-dom";
class NavBar extends Component {
render() {
return (
<div>
<ul>
<li>
<Link to="/propertytypes">Props!</Link>
</li>
<li>
<Link to="/entitytypes">Ent!</Link>
</li>
<li>
<Link to="/associationtypes">Ass!</Link>
</li>
</ul>
</div>
);
}
}
export default NavBar;
After clicking Props link
Besides what #Ukasyah noticed about disparity between the Router you are using (you say you are using BrowserRouter) and the screen captures with the URL you are getting (that points out you are using HashRouter), you must be getting a problem with the code you are showing up because the <Link> component in order to work must be contained inside the BrowserRouter. In your browser console it must be happening this error:
Warning: Failed context type: The context router is marked as
required in Link, but its value is undefined.
So to avoid the problem and links start to work, your render should be something like this:
<BrowserRouter>
<div>
<NavBar />
<Switch>
<Route path="/propertytypes" component={PropertyTypes} />
<Route path="/entitytypes" component={EntityTypes} />
<Route path="/associationtypes" component={AssociationTypes} />
<Route path={Routes.ROOT} component={Test} />
</Switch>
</div>
</BrowserRouter>
Note that I put the NavBar component inside the div because BrowserRouter only allows to have a single child.
I have been looking at different SO questions to solve this issue and none of them helped. My problem was using BrowserRouter in multiple different components. Same as here.
For me, the issue was that my entire app was wrapped with a <Router>, because that was how the boilerplate code was set up. Then I was copying snips from BrowserRouter docs, and did not remove the <BrowserRouter> wrapper around the code. Nested routers won't work properly.
The mistake I made was, I started with the setup from the documentation, which involves using:
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
Then I started splitting everything into separate layout files like this. So I initially copied the whole import between multiple files. At some point I was cleaning up the code and realized I only needed to import the Switch but I foolishly forgot to remove the BrowserRouter as, and I ended up with:
import { BrowserRouter as Switch } from "react-router-dom";
Which is obviously wrong since it mapped BrowserRouter to Switch, you can't have nested BrowserRouter 's and that's what introduced the issue in my case.

Hide App Elements React

I have an <App/> component which renders for any page on my site:
const App = () => (
<div>
<Header />
<Main />
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
)
export default App;
The problem I'm having now is that I have a Component (page) which doesn't include any of the components within <App /> aside from <Main /> (which is the router).
I'm puzzled on how to do this, since App.js is the parent component of all components. My only idea of how to do this (possibly) is that when a user clicks a <Link /> to the aforementioned component, I could add setState (maybe?) to App.js and change it to something like hideAppComponents = true and then hide the appropriate components. I know that in this case I would have to make <App /> extends Component since it would then be stateful.
Are there any suggested approaches for a use case like this?
As far as answering your specific question: Yes, adding state to your App and then rendering differently depending on the page would work.
However, a small refactoring of your components would make your problem easier.
In my opinion, a good use of <app> within the context of routing is to just use it to reference which route the user will be on.
<app>
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route exact path='/about' component={AboutUs}/>
<Route path='/somePageWithoutAFooter' component={CoolPage}/>
</Switch>
</main>
</app>
Now, you have set just a very set of minimal constraints from your top-level app. Depending on the route, you will render a specific child component. So this solves your direct problem. Now you can have CoolPage be its own custom thing, but then the Home page can do something else.
So far, so good. However lets say that both Home and AboutUs have the same basic template of the header and the subfooter that you've been talking about. It would be unfortunate for both of these components to have to describe this architecture inside the render. Instead, you could make a container component like this:
class MyLayout extends Component {
render() {
<div>
<Header />
{this.props.children}
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
}
}
And this component can be used like this:
<MyLayout><Home></MyLayout>
So now, all you need to do is to wrap all of your normal pages in a MyLayout. This can either be done in the app itself, or in a child if it gets more complicated.
Edit: This example uses react-router since this post was tagged with it. You can follow the same principles without using the router if you want. It just makes the <Route> stuff easier to manage.
the only possible solution i can think other than your solution is to use loaction prop. Below is the sample code you can try.
import STORE from './store/STORE';
import {Provider} from 'react-redux';
import {Route, Router} from 'react-router-dom';
import createHashHistory from 'history/createHashHistory';
const history = createHashHistory();
render(
<Provider store={STORE}>
<Router history={history}>
<Route path="/" component={App}/>
</Router>
</Provider>, document.getElementById('app')
);
const App = (location) => (
location.pathname.includes("error") ?
<div>
<Main />
</div> :
<div>
<Header />
<Main />
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
)
export default App;

Categories

Resources