Getting 404 in GitHub Pages on redirection - reactjs

I'm trying to learn how to use GitHub Pages with a basic React project. But I'm having an issue with the URL of the different pages of the project (like /home /about...).
I have a GH Page here: https://naacho20.github.io/itis/
If u try to use the navbar, a 404 would appear, but thats wrong because I have a Router redirecting that. I show my code so I can explain better:
App.js:
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import { BrowserRouter, Route } from "react-router-dom";
import Navbar from "./components/Navbar";
import Home from "./pages/Home";
import About from "./pages/About";
import Portfolio from "./pages/Portfolio";
import Contact from "./pages/Contact";
export default function App() {
return (
<div>
<BrowserRouter>
<Navbar />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/contact" component={Contact} />
</BrowserRouter>
</div>
);
}
Contact.js
import React from "react";
export default function Contact() {
return <div>Contact</div>;
}
Navbar.js
import React from "react";
import { withRouter } from "react-router-dom";
import { Navbar, Nav } from "react-bootstrap";
const menuItems = [
{
to: "/",
title: "Inicio",
},
{
to: "/about",
title: "Sobre mí",
},
{
to: "/portfolio",
title: "Portfolio",
},
{
to: "/contact",
title: "Contacto",
},
];
class NavBar extends React.Component {
getNavLinkClass = (path) => {
return this.props.location.pathname === path ? "active" : "";
};
render() {
return (
<div>
<Navbar bg="dark" expand="lg" variant="dark">
<Navbar.Brand href="/">IT.IS</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto">
{menuItems.map((item, index) => {
return (
<Nav.Link
key={index}
className={this.getNavLinkClass(item.to)}
href={item.to}
>
{item.title}
</Nav.Link>
);
})}
</Nav>
</Navbar.Collapse>
</Navbar>
</div>
);
}
}
NavBar = withRouter(NavBar);
export default NavBar;
So I see thats a problem from the URL, I see when I start the app, this goes to localhost:3000/itis and the Home page don't render, but if I remove the itis (localhost:3000/) it render the Home Page. I don't know what I'm doing wrong, any suggestion?
Ty.

This is because you are using SPA app so your all routes serving from one html file. You should use HashRouter to fix it. It is so simple you should import HashRouter instead of
BrowserRouter
import { BrowserRouter} from "react-router-dom";
to
import { HashRouter } from "react-router-dom";
and wrap it with your App
Also you have to wrap your Routes with Switch like this
<BrowserRouter>
<Switch>
<Navbar />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/contact" component={Contact} />
</Switch>
</BrowserRouter>

Related

Error: useHref() may be used only in the context of a <Router> component

**When i Write my My Nav Bar Component Content Directly in My Router Component. It works Fine But When I write that content in a NavBar Component it Generates the following error
Error: useHref() may be used only in the context of a component.
.**
Im Using
"react-dom": "^17.0.2", "react-router-dom": "^6.0.0-beta.6",
Following are my Components..
My NavBar Component:-
import { Link } from "react-router-dom";
// import styles from './NavBar.module.css';
export const NavBar = () => {
return (
<nav>
<Link to="/"> Home </Link>
<Link to="/about"> About </Link>
<Link to="/product"> Product </Link>
</nav>
);
}
My Route Component:-
import { BrowserRouter as Router, Switch, Route, Routes} from "react-router-dom";
// importing Component's
import { Home } from "./Components/Home/Home";
import { About } from "./Components/About/About";
import { Products } from "./Components/Products/Products";
import { ProductItems } from "./Components/ProductItems/ProductItems";
import {NavBar} from "./Components/NavBar/NavBar";
import { Fotter } from "./Components/Fotter/Fotter";
export const RouterConfig = () => {
return (
<Router>
<NavBar />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route exact path="/product" component={Products} />
<Route path="/product/:id" component={ProductItems} />
<Route path="*" component={() => <h2>404 Not Found </h2>} />
</Switch>
{/* <Fotter />' */}
</Router>
);
};
import {BrowserRouter as Router} from "react-router-dom";
Use in components App.js or above in index.js and wrap your component in Router.
Then the problem will disappear ;-)
In Your case I see two option:
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>,
document.getElementById("root")
);
OR use App Component instead of RouterConfig Component.
App.js
import { BrowserRouter as Router, Switch, Route, Routes} from "react-router-dom";
// importing Component's
import { Home } from "./Components/Home/Home";
import { About } from "./Components/About/About";
import { Products } from "./Components/Products/Products";
import { ProductItems } from "./Components/ProductItems/ProductItems";
import {NavBar} from "./Components/NavBar/NavBar";
import { Fotter } from "./Components/Fotter/Fotter";
export const App = () => {
return (
<Router>
<NavBar />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route exact path="/product" component={Products} />
<Route path="/product/:id" component={ProductItems} />
<Route path="*" component={() => <h2>404 Not Found </h2>} />
</Switch>
{/* <Fotter />' */}
</Router>
);
};
I tried to explain it as best I could. Hope this helps you ;-) Best Greetings and Good Luck!
If you're still confused, check out here =>
React Router V6 - Error: useRoutes() may be used only in the context of a <Router> component
export is not running properly and causing an error. Can you retype it like below and try?:
import { Link } from "react-router-dom";
const NavBar = () => {
return (
<div>
<Link to="/"> Home </Link>
<Link to="/about"> About </Link>
<Link to="/product"> Product </Link>
</div>
);
}
export default Navbar;
Also, you don't need curly brace for import statement.
import NavBar from "./Components/NavBar/NavBar";
If problem still persists, you can check your file paths because you are repeating folder names twice, it looks suspicious to me. Maybe you mean this:
import NavBar from "./Components/NavBar";

Error: Invariant failed: You should not use <Link> outside a <Router> when I try to test my app using localhost

I'm getting an error when I try to test my app on localhost:3000 in the Router, how can I fix it? I'm newbie in React & React Router also, what kind of problems can cause this.
App.js:
import { NavBar } from "./shared/NavBar"
import { Switch, Route } from "react-router-dom";
import { BooksList } from "./BooksList";
import { CreateBook } from "./CreateBook";
import { UpdateBook } from "./UpdateBook";
function App() {
return (
<>
<NavBar />
<Switch>
<Route path="/create-book">
<CreateBook />
</Route>
<Route path="/update-book">
<UpdateBook />
</Route>
<Route path="/">
<BooksList />
</Route>
</Switch>
</>
);
}
export default App;
NavBar component:
import { Flex, Image, Box, Link as StyledLink } from "rebass/styled-components";
import { Link } from "react-router-dom";
export const NavBar = () => {
return (
<Flex bg="black" color="white" justifyContent="center">
<Flex px={2} width="100%" alignItems="center">
<Link component={StyledLink} variant="nav" to="/">
React CRUD App
</Link>
<Box mx="auto" />
<Link component={StyledLink} variant="nav" to="/create-book">
Add new item
</Link>
</Flex>
</Flex>
)
}
Wrap your routing to BrowserRouter
import
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
and wrap routes
function App() {
return (
<Router>
<div>
<NavBar />
<Switch>
<Route path="/create-book">
<CreateBook />
</Route>
<Route path="/update-book">
<UpdateBook />
</Route>
<Route path="/">
<BooksList />
</Route>
</Switch>
</div>
</Router>
);
}

React Route render different banner image for each route

This is my Layout page where the routing is performed:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Header from './Header';
import Footer from './Footer';
import Banner from './Banner';
import Home from './Home';
import About from './About';
import Services from './Services';
import Book from './Book';
function Layout() {
return(
<Router>
<Header/>
<Banner/>
<Route exact path="/" component={Home}/>
<Route exact path="/Home" component={Home}/>
<Route exact path="/About" component={About}/>
<Route exact path="/Services" component={Services}/>
<Route exact path="/Book" component={Book}/>
<Footer/>
</Router>
)
}
export default Layout;
This is the Banner component:
import React from 'react';
import Jumbotron from 'react-bootstrap/Jumbotron';
function Banner(props) {
const heroStyle = {
backgroundImage: "url(" + require('../images/home-hero-image.jpg') + ")"
};
return (
<div>
<Jumbotron style={heroStyle}>
<h1 className="centerme">Live your best life</h1>
<p className="centerme">
Get Coaching
</p>
</Jumbotron>
</div>
);
}
export default Banner;
Basically I have a different banner image for Home, About and Services and want to update the image url depending on the page that is currently in use.
I'm not sure what the best practice way to achieve this would be.
You should be able to render the Banner after adding the router props to it, and then access location.pathname inside Banner.
Note withRouter and BannerWithRouter component:
import React from 'react'
import { BrowserRouter as Router, Route, withRouter } from 'react-router-dom'
import Header from './Header'
import Footer from './Footer'
import Banner from './Banner'
import Home from './Home'
import About from './About'
import Services from './Services'
import Book from './Book'
const BannerWithRouter = withRouter(({ location }) => <Banner {...props} />)
function Layout() {
return (
<Router>
<Header />
<BannerWithRouter />
<Route exact path='/' component={Home} />
<Route exact path='/Home' component={Home} />
<Route exact path='/About' component={About} />
<Route exact path='/Services' component={Services} />
<Route exact path='/Book' component={Book} />
<Footer />
</Router>
)
}
export default Layout
Banner component: (Note you now have a prop called location)
import React from 'react'
import Jumbotron from 'react-bootstrap/Jumbotron'
function Banner({ location }) {
const heroStyle = {
backgroundImage: 'url(' + require('../images/home-hero-image.jpg') + ')'
}
console.log(location.pathname)
if (location.pathname === '/about') {
return 'This is the about page'
}
return (
<div>
<Jumbotron style={heroStyle}>
<h1 className='centerme'>Live your best life</h1>
<p className='centerme'>
<a href='#' className='jumbotron-book-now-button'>
Get Coaching
</a>
</p>
</Jumbotron>
</div>
)
}
export default Banner

How can I redirect users to different pages with Link

I have the code like bellow. I want when I click in the link it should direct me to the other page.
But It doesn't do anything. Could someone please help with this?
<Link className="portfolio-link" data-toggle="modal" to={`/blog/${this.props.post.slug}`}>
<div className="portfolio-hover">
<div className="portfolio-hover-content">
<i className="fas fa-plus fa-3x"></i>
</div>
</div>
{this.props.post.PostImage ? this.props.post.PostImage.length > 0 ? <img style={{width: '100%'}} className="img-fluid" src={API.makeFileURL(this.props.post.PostImage[0].thumbnail, null)} alt="/"/>
: null: null}
</Link>
You may create separate component for navigation purpose where you may put all of your url links
NavBar component
import React from "react";
import { Link } from "react-router-dom";
const NavBar = ({ menuData }) => {
return (
<nav>
<ul>
{menuData.map(menu => {
return (
<li>
<Link to={menu.path}>
{menu.name}
</Link>
</li>
);
})}
</ul>
</nav>
);
};
export default NavBar;
You have to ensure the route section, this section specially manage your route and it will redirect you to your desired page/component based on url change
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/" component={Home} />
</Switch>
So I keep the NavBar and the route closely in App.js
App.js
import React, { Component } from "react";
import NavBar from "./navbar";
import { Route, Redirect, Switch } from "react-router-dom";
import "./App.css";
class App extends Component {
state = {
navBars: [
{ name: "Home", path: "/" },
{ name: "Login", path: "/login" }
]
};
render() {
return (
<React.Fragment>
<main>
<NavBar
menuData={this.state.navBars}
></NavBar>
<div className="content">
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/" component={Home} />
</Switch>
</div>
</main>
</React.Fragment>
);
}
}
export default App;
And finally you have to make sure your navbar/Link and Routes should be under Router, So BrowserRouter confirm this thing
<BrowserRouter>
<App />
</BrowserRouter>
You may have a look in my index.js
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter} from "react-router-dom";
import "./index.css";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
Hope it will help you

How to show/hide reactstrap navbar in Reactjs Redux application?

I want to show/hide the navigation bar depending upon logged in status of the user. Once the user is authenticated, I store the access-token in local storage. I have tried to show/hide the navigation bar by checking if access-token exists or not. But it needs a hard refresh.
Please find the header component: /components/app-header.js
const AppHeader = () => (
<Navbar color="light" light expand="md">
<NavbarBrand href="/">TestBrand</NavbarBrand>
<Nav navbar>
<NavItem>
<Link className="lnk" to='/users'>Users</Link>
</NavItem>
</Nav>
<Nav className="ml-auto" navbar>
<NavItem>
<Link className="lnk" to='/logout'>Logout</Link>
</NavItem>
</Nav>
</Navbar>
)
The file which handles all the routes is as below (routes/index.js):
import React from 'react';
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom';
import { AppHeader } from '../components';
export default () => (
<BrowserRouter>
<div>
{
localStorage.getItem('access-token') &&
<div>
<AppHeader />
</div>
}
<Switch>
<Route exact path="/users" component={Users} />
<Route exact path="/users/add" component={Users} />
<Route exact path="/users/:id" component={Users} />
</Switch>
</div>
</BrowserRouter>
)
The main App just contains the following code:
import React, { Component } from 'react';
import Routes from '../routes';
import '../style.css';
class App extends Component {
render() {
return (
<div>
<Routes />
</div>
)
}
}
export default App;
I do not want to refresh the page, as it defeats the very purpose of SPA. How can I achieve that?
Make Routes a stateful Component.
import React from 'react';
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom';
import { AppHeader } from '../components';
class Routes {
this.state = {loggedIn: false}
componentDidMount() {
if(localStorage.getItem('access-token')) {
this.setState({loggedIn: true})
}
//attach an event listener to the window object for storage event.
$(window).on('storage',() => {
if(localStorage.getItem('access-token')) {
this.setState({loggedIn: true})
}
});
}
render() {
return (
<BrowserRouter>
<div>
{
this.state.loggedIn &&
<div>
<AppHeader />
</div>
}
<Switch>
<Route exact path="/users" component={Users} />
<Route exact path="/users/add" component={Users} />
<Route exact path="/users/:id" component={Users} />
</Switch>
</div>
</BrowserRouter>)
}
}
export default Routes;
After the component is mounted you are listening to localStorage updates. if local storage is changed it will update the state of the component as required.

Resources