I have been working with react-router-dom v4 and i am trying to make a central config for the routes with a workaround.
This is my routes.js
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import {
WebsiteFilter,
WebsiteLeaderBoard,
WebsiteGraph,
WebsiteQues
}
from "./components";
import { DashboardApp ,LeaderBoardApp} from "./containers";
const dashboardContainer = (id) => (
<DashboardApp key={id}>
<Switch>
<Route exact path="/dashboard" render={(props) => (
<>
<WebsiteFilter />
<WebsiteGraph />
<WebsiteQues />
</>
)}
/>
</Switch>
</DashboardApp>
);
const leaderBoardContainer = (id) => (
<LeaderBoardApp key={id}>
<Switch>
<Route exact path="/leaderboard" render={(props) => (
<>
<WebsiteLeaderBoard />
</>
)} />
</Switch>
</LeaderBoardApp>
);
const container = [ dashboardContainer , leaderBoardContainer ];
const Routes = () => {
return (
<BrowserRouter baseName="/">
<Switch>
{container.map((pages,id) => (
pages(id)
))}
</Switch>
</BrowserRouter>
);
};
export default Routes;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
This is my DashboardApp.js
import React, { Component } from "react";
import { WebsiteHeader , WebsiteFooter} from "../components";
import PropTypes from "prop-types";
import classes from "./app.scss";
class DashBoardApp extends Component {
render() {
return (
<div className={classes.app}>
<WebsiteHeader/>
<>
{this.props.children}
</>
<WebsiteFooter />
</div>
);
}
}
export default DashBoardApp;
DashBoardApp.propTypes = {
children : PropTypes.element,
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
This is my LeaderBoardApp.js
import React, { Component } from "react";
import { WebsiteHeader , WebsiteFooter} from "../components";
import PropTypes from "prop-types";
import classes from "./app.scss";
class LeaderBoardApp extends Component {
render() {
return (
<div className={classes.app}>
<WebsiteHeader/>
<>
{this.props.children}
</>
<WebsiteFooter />
</div>
);
}
}
export default LeaderBoardApp;
LeaderBoardApp.propTypes = {
children : PropTypes.element,
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I have set my Link:
export default function HeaderLink (props) {
const { wrapperClass, dashboardClass } = props;
return (
<ul className={wrapperClass}>
<li className={[dashboardClass,classes.active].join(" ") }><Link to ="/dashboard">Dashboard</Link></li>
<li className={dashboardClass}> <Link to ="/leaderboard">Leaderboard</Link></li>
</ul>
);
}
According to this the link should work , but when i try to click the leaderboard link , it doesn't render the Websiteleaderboard component. But it always render the First route when i click the dashboard link as it's the first after switch statement.
I searched online , and thought about it a lot , but couldn't found any solution. I don't know what's the problem here.
Here's the picture of rendered routes:
First pic
Second pic
You have multiple <Switch> elements in what you're trying to do. From the docs:
When a <Switch> is rendered, it will only render the first child that matches the current location.
Docs here
Removing all the switches except the wrapper should work. However, might I suggest a cleaner approach:
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import {
WebsiteFilter,
WebsiteLeaderBoard,
WebsiteGraph,
WebsiteQues
}
from "./components";
import { DashboardApp ,LeaderBoardApp} from "./containers";
const dashboardContainer = () => (
<DashboardApp>
<WebsiteFilter />
<WebsiteGraph />
<WebsiteQues />
</DashboardApp>
);
const leaderBoardContainer = () => (
<LeaderBoardApp>
<WebsiteLeaderBoard />
</LeaderBoardApp>
);
const Routes = () => {
return (
<BrowserRouter baseName="/">
<Switch>
<Route path="/dashboard" component={dashboardContainer} />
<Route path="/leaderboard" component={leaderBoardContainer} />
</Switch>
</BrowserRouter>
);
};
export default Routes;
By doing this, your entire configuration is contained in the Routes. You could even move the components out of that file, and have your Routes contained to only the actual routes, while importing the components you want to use.
Related
I am trying to use react fullpageJS and react router dom to create a carousel but it shows empty screen, Here's the code I am using:
APP.JS:
import { Route, Routes } from "react-router-dom";
import Navigation from "./routes/navigation/navigation.component";
import Home from "./components/home/home.component";
function App() {
const About = () => {
return (
<div>
<h1>This is about</h1>
</div>
);
};
return (
<div>
<Routes>
<Route path="/" element={<Navigation />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
</Route>
</Routes>
</div>
);
}
export default App;
Home.jsx:
import { useState, useEffect, React } from "react";
import ProjectPreview from "../project-preview/project-preview.component";
import ReactFullpage from "#fullpage/react-fullpage";
// import "fullpage.js/vendors/scrolloverflow";
import PROJECTS_DATA from "../../Projects";
const Home = () => {
const [projectsToPreview, setProjects] = useState([]);
useEffect(() => {
setProjects(PROJECTS_DATA);
}, []);
<ReactFullpage
render={() => {
return (
<ReactFullpage.Wrapper>
<ReactFullpage.Wrapper>
{projectsToPreview.map((project) => {
return (
<div className="section" key={project.id}>
<h1>Test</h1>
<ProjectPreview project={project} />
</div>
);
})}
</ReactFullpage.Wrapper>
</ReactFullpage.Wrapper>
);
}}
/>;
};
export default Home;
The rendered screen shows only the navbar component but the content in the slider appear neither on the screen nor in the javascript dom
index.js:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
reportWebVitals();
Navigation.jsx
import { Link, Outlet } from "react-router-dom";
import { Nav, Navbar } from "react-bootstrap";
const Navigation = () => {
return (
<>
<Navbar expand="lg" variant="dark">
<Link className="navbar-brand" to="/">
LOGO
</Link>
<Nav className="ms-auto">
<Link className="nav-link" to="/about">
About
</Link>
</Nav>
</Navbar>
<Outlet />
</>
);
};
export default Navigation;
I suspect the issue is that the Navigation component isn't rendering an Outlet component for the nested routes to render their element into.
Navigation should render an Outlet.
Example:
import { Outlet } from 'react-router-dom';
const Navigation = () => {
...
return (
... nav and layout UI
<Outlet /> // <-- nested routes render content here
...
);
};
I have a Link in my Footer.js, and for some reason, it's not working as links in the browser. Like not showing up a pointer on the link etc. I have multiple Links in my Nav component. They all are working fine, but if I place a Link in any other component, it doesn't work. I have tried using BrowserRouter instead of HashRouter and NavLink instead of Link, but the problem still exists. It seems like a reckless mistake, though.
For now, I have this as a static website. That's why I haven't wrapped my components in Switch and Route.
Footer.js
import { Link } from 'react-router-dom'
const Footer = () => {
return (
<div>
<h1>Create group!</h1>
<Link to="/" className="rounded">Get Started</Link>
</div>
)
}
export default Footer
App.js:
import Footer from './Footer'
import { HashRouter } from 'react-router-dom'
const App = () => {
return (
<HashRouter basename="/">
<Nav />
<Home />
<About />
<HowItWorks />
<GroupCarousel />
<EventCarousel />
<Footer />
</HashRouter>
);
}
export default App;
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Any help would be appreciated.
You have to define your routes inside HashRouter using Switch and Route tags which is to be used inside the app. Otherwise your routes won't work. Try following code and it will work as expected.
Footer.js
import { Link } from 'react-router-dom'
const Footer = () => {
return (
<div>
<h1>Create group!</h1>
<Link to="/" className="rounded">Get Started</Link>
</div>
)
}
export default Footer
App.js
import Footer from './Footer'
import { HashRouter } from 'react-router-dom'
const App = () => {
return (
<HashRouter basename="/">
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</HashRouter>
);
}
export default App;
Home.js
import React from 'react'
...
const Home = () => {
return (
<>
<Nav />
<Home />
<About />
<HowItWorks />
<GroupCarousel />
<EventCarousel />
<Footer />
</>
):
}
export default Home;
My initial question was
How to add url params without the whole page reloading?
#Ajeet Shah told me in the comments that the page shouldn't reload if the pathname is the same. So I figured the problem lies elsewhere. I could pin point the problem and found out it has to do with code splitting, I could even create a reproducible example here.
The problem is the following: When part of the code is loaded asynchronously and it contains routes, calls to history.push() with the exact same pathname make the page reload.
example.js
import React from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import AsyncComponent from "./components/AsyncComponent";
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about/test">About</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<AsyncComponent />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
AsyncComponent.jsx
import React, { Suspense } from "react";
const Component = React.lazy(() => import("./Routes"));
export const AsyncComponent = (props) => {
return (
<Suspense fallback={<div>...loading</div>}>
<Component />
</Suspense>
);
};
export default AsyncComponent;
Routes.jsx
import React, { useEffect } from "react";
import { Switch, Route } from "react-router-dom";
import { useRouteMatch } from "react-router";
import About from "./About";
export const Routes = (props) => {
let { path } = useRouteMatch();
console.log("rendering Routes");
useEffect(() => {
console.log("mounting Routes");
}, []);
return (
<Switch>
<Route exact path={`${path}/test`}>
<About />
</Route>
</Switch>
);
};
export default Routes;
About.jsx
import React, { useEffect } from "react";
import { useHistory } from "react-router";
import { Link } from "react-router-dom";
export const About = () => {
console.log("rendering About");
useEffect(() => {
console.log("mounting About");
}, []);
const h = useHistory();
return (
<div>
<Link
to={{
pathname: "/about/test",
search: "foo=1&bar=2"
}}
>
Push search params to About
</Link>
<button
onClick={() => {
h.push({
pathname: "/about/test",
search: "foo=1&bar=2"
});
}}
>
Push search params to About
</button>
<h2>About</h2>
</div>
);
};
export default About;
What am I doing wrong? Is there a way to avoid this while keeping code-splitting?
I'm trying to make my page flexible to show different navigation bars depending on the page I'm on. When I run the page with the code presented below it shows the different navs as they should, but the actualRouteComponent is not showing the content of the route component eg. FrontpageRoute, BookRoute.
This is my App.js:
import React from 'react';
import {BrowserRouter as Router, Switch} from 'react-router-dom';
import './Mystyles.scss';
//Routes
import DynamicLayout from './layout/DynamicLayout'
import FrontpageRoute from './routes/FrontpageRoute';
import BookRoute from './routes/BookRoute';
function App() {
return (
<Router>
<div className="App">
<Switch>
<DynamicLayout
exact
path="/"
component={FrontpageRoute}
/>
<DynamicLayout
exact
path="/book"
component={BookRoute}
layout="SUB_NAV"
/>
</Switch>
</div>
</Router>
);
}
export default App;
This is my DynamicLayoutRoute.js:
import React from 'react';
import {BrowserRouter as Route} from 'react-router-dom';
import Header from './../components/Header';
import MainNavigation from '../components/MainNavigation';
const DynamicLayout = props => {
const { component: RoutedComponent, layout, ...rest } = props;
const actualRouteComponent = (
<Route
{...rest}
render={props => (
<RoutedComponent {...props} />
)}
/>
);
switch (layout) {
case 'MAIN_NAV': {
return (
<div>
<MainNavigation />
<Header />
{actualRouteComponent}
</div>
)
}
case 'SUB_NAV': {
return (
<div>
<MainNavigation />
<h2>Sub Nav</h2>
<Header />
{actualRouteComponent}
</div>
)
}
default: {
return (
<div>
<MainNavigation />
<Header />
{actualRouteComponent}
</div>
)
}
}
};
export default DynamicLayout;
and here is my MainNavigation.js:
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
class MainNavigation extends Component {
render() {
return (
<nav className="main-navigation">
<div className="main-navigation--content">
<div className="mobil-nav">
<span>Burger</span>
</div>
<div className="link-list">
<NavLink exact to="/">Frontpage</NavLink>
<NavLink exact to="/book">Book</NavLink>
</div>
<div className="social">
<span>Instagram</span>
</div>
</div>
</nav>
)
}
}
export default MainNavigation
Can someone tell me what is wrong?
I see that in your DynamicLayoutRoute component you are accessing props as this.props. this is undefined in functional components.
Access props like this -
const DynamicLayoutRoute = props => {
const { component: RoutedComponent, layout, ...rest } = props;
...
}
Hi all I am currently stuck with the following:
Cannot read property 'isLoggedIn' of null
> 9 | const Header = () => {
10 | const {isLoggedIn} = useContext(AuthContext);
11 | return (
12 | <ul className="nav">
I am new in React and I was following a tutorial to implement a sign-in/sign-up form and sending data to firebase (which is also something completely new to me). I was able to fix a couple of previous issues on my own but I am now stuck at this one.
If I don't import the Header into the Routing the site works fine but as soon as I try to import it in any way to Routing.js it's failing.
Header.js
import React, { useContext } from "react";
import routes from "./routes";
import { Link } from "react-router-dom";
import { AuthContext } from "./test";
const Header = () => {
const {isLoggedIn} = useContext(AuthContext);
return (
<ul className="nav">
{routes.map((route, i) => (
<li key={i}>
<Link to={route.path}>{route.name}</Link>
</li>
))}
{isLoggedIn && <li><Link to="/reports">Profile</Link></li>}
</ul>
)
}
export default Header;
Routing.js
import React from "react";
import Head from "./Head";
import Join from "./Join";
import Login from "./Login";
import Test from "./test";
import HomePage from "./HomePage";
import Header from "./Header";
import { BrowserRouter as Router, Switch, Route, Link} from "react-router-dom";
function Home() {
return (
<div className="App">
<Head />
<HomePage />
</div>
);
}
function Reviews() {
return (
<div className="App">
<Head />
</div>
);
}
function Logging() {
return (
<div className="App">
<Head />
<Header />
<Test />
</div>
);
}
function Signup() {
return (
<div className="App">
<Head />
<Header />
<Test />
</div>
);
}
function App() {
return (
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/review" exact component={Reviews} />
<Route path="/login" exact component={Logging} />
<Route path="/signup" exact component={Signup} />
</Switch>
</Router>
)
}
export default App;
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { Switch, BrowserRouter as Router, Route } from "react-router-dom";
import routes from "./routes.js";
import Header from "./Header";
import "./styles.css";
import * as firebase from "firebase";
import firebaseConfig from "./firebase.config";
import protectedRoutes from './protectedRoutes'
import ProtectedRouteHoc from './ProtectedRouteHoc'
firebase.initializeApp(firebaseConfig);
export const AuthContext = React.createContext(null);
function Test() {
const [isLoggedIn, setLoggedIn] = useState(false);
function readSession() {
const user = window.sessionStorage.getItem(
`firebase:authUser:${firebaseConfig.apiKey}:[DEFAULT]`
);
if (user) setLoggedIn(true)
}
useEffect(() => {
readSession()
}, [])
return (
<AuthContext.Provider value={{ isLoggedIn, setLoggedIn }}>
Is logged in? {JSON.stringify(isLoggedIn)}
<div className="App">
<Router>
<Header isLoggedIn={isLoggedIn}/>
<Switch>
{protectedRoutes.map(route => (
<ProtectedRouteHoc
key={route.path}
isLoggedIn={isLoggedIn}
path={route.path}
component={route.main}
exact={route.exact}
public={route.public}
/>
))}
{routes.map(route => (
<Route
key={route.path}
path={route.path}
exact={route.exact}
component={route.main}
/>
))}
</Switch>
</Router>
</div>
</AuthContext.Provider>
);
}
export default Test;
I would appreciate any tips or things I can read through to get a better understanding in this.
You're destructing the return value of useContext(AuthContext). You're expecting it to return an object with a key isLoggedIn, e.g. { isLoggedIn: false }, but it's returning null instead. You probably haven't given it a default value when you instantiated the context instance, e.g.
// Possibly what you're doing, no default value
const AuthContext = React.createContext() // null
// Instantiated with a default value
const AuthContext = React.createContext({ isLoggedIn: false })