Managing routing by Link in grandchild component - javascript

I have an App component, that has child component NavigationBar. That NavigationBar also has children, those are NavigationBarTabs. What I want to do, is to manage routing in App component, but have links in NavigationBarTabs. If I do it this way, I can only get new content in App by refreshing. If I keep links in App component it works fine, but obviously I would like those links to be in NavigationBarTabs. Is there any way I can do that? Examples below:
Works after clicking link:
<BrowserRouter>
<Route path ='/Profile' component = {Profile}/>
<Route path ='/About' component={About}/>
<Route path ='/Catalog' component={Catalog}/>
<Link to={'/Profile'}>Profile</Link>
<Link to={'/Catalog'}>Catalog</Link>
<Link to={'/About'}>About</Link>
</BrowserRouter>
Works after clicking link and refreshing page:
<BrowserRouter>
<NavigationBar/> <--- Tabs with Links are stored there, same 'to' prop
<Route path ='/Profile' component = {Profile}/>
<Route path ='/About' component={About}/>
<Route path ='/Catalog' component={Catalog}/>
</BrowserRouter>

Wrapping top component in solved the problem

I had a similar issue where I wanted my links to be in a sliding side bar.
here is a way I found worked for me.
Routes Component: I imported the components which i would like to route to into my routes component. As below.
import React, {Component} from 'react'
import {BrowserRouter, Route, Link} from 'react-router-dom';
import Component from './component.js';
const routes = [
{
path: '/',
exact: true,
main: () => <place component here/>
},
{
path: '/dogs',
main: () => <place component here/>
},
{
path: '/cats',
main: () => <place component here/>
}
];
export default routes;
Sidebar Component: I then placed my links in my sidebar component as below.
import React from 'react';
import './SideDrawer.css';
import {BrowserRouter, Route, Link} from 'react-router-dom';
const sideDrawer extends Component{
render(){
return(
<nav className='sidebar'>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/dogs'>Dogs</Link></li>
<li><Link to='/cats'>Cats</Link></li>
</ul>
</nav>
);
}
};
export default sideDrawer;
Then in my App.js component which will render my page I made the following imports:
import React, {Component} from 'react';
import SideDrawer from './components/SideDrawer/SideDrawer';
import {BrowserRouter, Route, Link} from 'react-router-dom';
import routes from './components/routes/routes.js';
Then included the following in my return statement.
return(
<div style={{height:'100%'}}>
<BrowserRouter>
<SideDrawer/>
<main>
{routes.map((route) => (
<Route
key={route.path}
path={route.path}
exact={route.exact}
component={route.main}
/>
))}
</main>
</BrowserRouter>
</div>
);
}
}
please note everything inside the App.js return statement is wrapped inside a BrowserRouter tag. Hope this can help you.

Related

White blank pages in my react application after using the react-router-dom to link pages

I have been receiving white blank pages when trying to create multiple pages within my app and I have been using the router-dom to try and fix this but still can't understand why. Here is my code with Home and Navigation js being inside a components folder in the src directory and App.js just inside the src directory.
App.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Home from './components/Home';
import Glazing from './components/Glazing';
import Navigation from './components/Navigation';
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Navigation />
<Route path="/" component={Home} exact/>
<Route path="/glazing" component={Glazing}/>
</div>
</BrowserRouter>
);
}
}
export default App;
Nav.js
import React from 'react';
import { NavLink } from 'react-router-dom';
const Navigation = () => {
return (
<div>
<NavLink to="/">Home</NavLink>
<NavLink to="/glazing">Glazing</NavLink>
</div>
);
}
export default Navigation;
Home.js
import React from "react";
import logo from '../logo.svg';
import './Home.css';
import "#fontsource/dm-sans";
function home() {
return (
<div className="Home">
<header className="Home-header">
<h1>EPC RATING PREDICTOR</h1>
</header>
<button> GET STARTED</button>
</div>
);
}
export default Home;
If you are using react-router-dom#6 then there are a couple things you need to address.
The Switch component was replaced by the Routes component and all Route components must be wrapped/rendered directly by Routes, or another Route component in the case of nesting routes.
The Route component API changed; gone are the component, and render and children function props, all replaced by a single element prop taking a ReactNode, a.k.a. JSX, value.
Example:
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './components/Home';
import Glazing from './components/Glazing';
import Navigation from './components/Navigation';
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/glazing" element={<Glazing />} />
</Routes>
</div>
</BrowserRouter>
);
}
}
See the Upgrading from v5 guide for other changes.

React-router <Route> tag not rendering component

I'm running into an issue where my route tag in specific is not rendering any components.
Steps I have tried:
Changed import of { Route } from "react-router-dom".
Changed paths to see if other paths render.
Rendered the component within tags (this worked).
The issue seems to be coming down to something going on with the tag.
Here is a copy of my code:
import { Component } from "react";
//import all components rendered
import NavBar from "./Nav";
import Orders from "./Orders";
import Cart from "./Cart";
import Menu from "./Menu";
import Login from "./Login.jsx";
import Home from "./Home.jsx";
// for routing
import { Route } from "react-router";
import { BrowserRouter } from "react-router-dom";
//main App to combine all components and be rendered
class App extends Component {
render() {
return (
<BrowserRouter>
<NavBar />
<Route path="/" exact component={Login} />
</BrowserRouter>
)
}
}
export default App;
The versions are:
├─┬ react-router-dom#6.2.1
│ └── react-router#6.2.1 deduped
└── react-router#6.2.1
I tried changing the tags to as per a suggestion and it still didn't work, but I may have implemented it incorrectly. Here is what I tried:
import { Component } from "react";
//import all components rendered
import NavBar from "./Nav";
import Orders from "./Orders";
import Cart from "./Cart";
import Menu from "./Menu";
import Login from "./Login.jsx";
import Home from "./Home.jsx";
// for routing
import { Route } from "react-router";
import { BrowserRouter, Routes } from "react-router-dom";
//main App to combine all components and be rendered
class App extends Component {
render() {
return (
<Routes>
<NavBar />
<Route path="/" exact component={Login} />
</Routes>
)
}
}
export default App;
The errors I am getting on the console are:
Uncaught Error: useRoutes() may be used only in the context of a <Router> component.
Choo 3
React 17
Choo 2
Webpack 3
The above error occurred in the <Routes> component:
Routes#http://localhost:3000/static/js/bundle.js:54433:7
App#http://localhost:3000/static/js/bundle.js:42:1
Any help would be greatly appreciated!
Solution:
Was resolved by switching the "component" tag to "element" tag and removing the tag outside as follows:
<>
<NavBar />
<Routes>
<Route path="/" exact element={<Login />} />
</Routes>
</>
List item
put Navbar outside for Routes tag like i did below
import { BrowserRouter, Routes,Route } from "react-router-dom";
//main App to combine all components and be rendered
class App extends Component {
render() {
return (
<>
<NavBar />
<Routes>
<Route path="/" element={<Login/>} />
</Routes>
</>
)
}
}
export default App;
also for newer version of react-router-dom use element instead of component and remove exact
It will be good if you use BrowserRouter index.js and wrapper App over there
for example index.js
<BrowserRouter><App/></BrowserRouter>
I ran into the same issue on react router v6, you need to wrap all your routes in the Routes component from react-router-dom.
Try this:
import { Component } from "react";
//import all components rendered
import NavBar from "./Nav";
import Orders from "./Orders";
import Cart from "./Cart";
import Menu from "./Menu";
import Login from "./Login.jsx";
import Home from "./Home.jsx";
// for routing
import { BrowserRouter, Route, Routes } from "react-router-dom";
//main App to combine all components and be rendered
class App extends Component {
render() {
return (
<BrowserRouter>
<NavBar />
<Routes>
<Route path="/" element={<Login/>} exact/>
</Routes>
</BrowserRouter>
)
}
}
export default App;

React app routing doesn't load content unless page reloaded

I've been working on a react single page app and have been trying to get the routing to work.
I believe the routing itself actually works however the page does not load the correct content unless the page is manually reloaded. Back and forward browser arrows also work.
For example I can navigate to localhost:3000 fine and the content is loaded correctly but when I press a button to navigate to localhost:3000/contacts nothing is displayed unless I refresh the page. Once manually refreshed the contacts page shows up. What gives?
index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router } from 'react-router-dom';
// Import App component
import App from './App'
// Import service workers
import * as serviceWorker from './serviceWorker'
// Render App component in the DOM
ReactDOM.render(
<Router>
<App />
</Router>
, document.getElementById('root')
)
serviceWorker.unregister()
App.tsx
// Import necessary dependencies
import React from 'react'
import Routes from './Routes'
// Create App component
function App() {
return (
<div className="App">
<Routes />
</div>
)
}
export default App
history.tsx
import { createBrowserHistory as history} from 'history';
export default history();
Home/Home.tsx
import React, { Component } from "react";
import history from './../history';
import "./Home.css";
export default class Home extends Component {
render() {
return (
<div className="Home">
hello home
<button onClick={() => history.push('/Contact')} value='click here'>Get Started</button>
</div>
);
}
}
Contact/Contact.tsx
import React, { Component } from 'react';
class Contact extends Component {
render() {
return (
<div>
hello world
</div>
);
}
}
export default Contact;
Routes.tsx
import React, { Component } from "react";
import {BrowserRouter, Router, Switch, Route } from "react-router-dom";
import Contact from "./Contact/Contact";
import Home from "./Home/Home"
import history from './history'
export default class Routes extends Component {
render() {
return (
<div>
<Router history={history}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/Contact" component={Contact} />
</Switch>
</Router>
</div>
)
}
}
Any help greatly appreciated
I think there's some extra code that might be causing conflict. You're defining the Router from react-router-dom twice:
Once here, in index.tsx
ReactDOM.render(
<Router> // here
<App />
</Router>
, document.getElementById('root')
)
and then again in Routes.tsx
<Router history={history}> // here
<Switch>
<Route path="/" exact component={Home} />
<Route path="/Contact" component={Contact} />
</Switch>
</Router>
You have to drop one of them, they're probably conflicting each other
Update
In addition to that, I think you should not use the history object directly from your export, but access it through the HOC withRouter. Then, you'd wrap
So you'd do something like this
import React, { Component } from "react";
import { withRouter } from 'react-router-dom'
import "./Home.css";
class Home extends Component {
const { history } = this.props
render() {
return (
<div className="Home">
hello home
<button onClick={() => history.push('/Contact')} value='click here'>Get Started</button>
</div>
);
}
}
export default withRouter(Home)
I think the issue here is that you need to wrap your pages with withRouter() like so:
import React, { Component } from "react";
import history from './../history';
import "./Home.css";
import { withRouter } from 'react-router-dom'; //<---------- add this
class Home extends Component {
render() {
return (
<div className="Home">
hello home
<button onClick={() => history.push('/Contact')} value='click here'>Get Started</button>
</div>
);
}
}
default export withRouter(Home); //<-------------- and add this
You will need to do the same on your Contact page as well.
Why do you have two routers?
I guess you simply need to remove the Router either in index.tsx or in Routes.tsx
According to you file naming I would remove the Router in Routes.tsx
It seems like you are using the history package for navigation. If you are using the react-router v5, then you may have to downgrade the history package to 4.10.1 until the history package developers issue a new release with the fix. As of writing this, the latest release version of history package is v5.0.1, and if you see a new release than this, you can try with that version first to see if it works, before doing the downgrade to 4.10.1
Issue Link -> https://github.com/remix-run/history/issues/804

How to make material ui sidebar to open the main content in react?

I am a newbie to react and currently developing an application,
BACKGROUND
It has admin, faculty, student, dashboards.amd a static landing page with buttons to go to /admin/login ,/faculty/login ,/student/login. which opens respective dashboards [![Once admin logins he gets this dashboard page ][1]][1]
PROBLEM:
App.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import Routes from "./routes";
import firebase from "./Firebase";
const App = props => {
return (
<BrowserRouter>
<Routes {...props} />
</BrowserRouter>
);
};
firebase.auth().onAuthStateChanged(user => {
ReactDOM.render(<App user={user} />, document.getElementById("root"));
});
Routes.js
import React from "react";
import { Switch, Route, BrowserRouter } from "react-router-dom";
import MainLayout from "./OtherComponents/Common/MainLayout";
//Home
import Home from "./MainComponents/Home";
import HomePublicRoute from "./OtherComponents/Routes/Home/HomePublicRoute";
//ADMIN
//components
import AdminLogin from "./OtherComponents/Login/Admin";
import AdminDash from "./MainComponents/Admin";
import AdminPublicRoute from "./OtherComponents/Routes/Admin/AdminPublicRoutes";
import AdminPrivateRoute fro"./OtherComponents/Routes/Admin/AdminPrivateRoutes";
//pages
import PageDashboard from "./MainComponents/Admin/pages/dashboard";
import AdminTaluka from "./MainComponents/Admin/pages/taluka";
const Routes = props => {
console.log(props);
return (
<MainLayout>
<Switch>
<AdminPublicRoute
{...props}
exact
restricted={true}
path="/admin/login"
component={AdminLogin}
/>
<AdminPrivateRoute
{...props}
path="/admin/admindashboard"
exact
component={AdminDash}
/>
<AdminPrivateRoute
{...props}
path="/admin/pagedashboard"
exact
component={PageDashboard}
/>
<AdminPrivateRoute
{...props}
path="/admin/taluka"
exact
component={AdminTaluka}
/>
<HomePublicRoute path="/" component={Home} />
</Switch>
</MainLayout>
);
};
export default Routes;
MainLayout.js
import React from "react";
//var reactRouterToArray = require("react-router-to-array");
const MainLayout = props => {
//console.log(reactRouterToArray(props.children));
return <div>{props.children}</div>;
};
export default MainLayout;
Sidebar doesn't open the content inside the main container instead it opens in a new tab if i use route inside routes.js .
Sidebar doesn't open the content if i use route inside AdminDash.js .
i have tried passing the routes using props (props.children) to AdminDash( its not receivng the prop)
I am using private and public routes.
I am confused and I don't know where am I going wrong any suggetions , or hints would be helpful.
Thanks in advance.
Sidebar doesn't open the content inside the main container instead it opens in a new tab if i use route inside routes.js .
Inside LeftDrawer you are rendering links to the content. You should use react-router-dom Link elements.
Like this:
import { Link } from 'react-router-dom'
<Link to="/about">About</Link>
Sidebar doesn't open the content if i use route inside AdminDash.js .
Routes shouldn't be defined multiple times. You have defined /admin/pagedashboard both in AdminDash.js and Routes.js. If you want to have a shared shell around the content, define routes inside the shell component and remove exact route from the parent routes.
Example:
MainLayout
.Routes
../admin
...AdminDash (Shell for multiple pages, admin layout)
..../admindashboard
.....AdminDasboard
..../pagedashboard
.....PageDashboard
i have tried passing the routes using props (props.children) to AdminDash( its not receivng the prop)
You should just import them when needed.
EDIT:
Remove exact from the Routes.js <Route path='/admin' component={AdminDash} /> and in AdminDash try
const AdminDash = ({ match }) => (
<div>
<Route path={${match.url}/admindashboard} component={AdminContent}/>
<Route path={${match.url}/pagedashboard} component={PageContent}/>
</div>
);
In the above example take note to change AdminContent and PageContent with the names of your components.

react router 4 nested components not working properly

I am switching from react-router 3.x to 4.x and I am not able to render nested routes.
I bootstrapped an application using create-react-app
index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './routes';
import './index.css';
ReactDOM.render(<Routes />, document.getElementById('root'));
routes.js file
import React from 'react';
import _ from 'lodash';
import {
BrowserRouter as Router,
Route,
} from 'react-router-dom';
import { dojoRequire } from 'esri-loader';
import EsriLoader from 'esri-loader-react';
import App from './components/App';
import Home from './components/Home';
/**
* Helper component to wrap app
*/
class AppWrapper extends React.Component {
/**
* Util function to render the children
* Whenever a state change happens in react application, react will render the component again
* and we wish to pass the updated state to the children as props
*/
renderChildren() {
const {children} = this.props;
if (!children) {
return;
}
return React.Children.map(children, c => React.cloneElement(c, _.omit(this.props, 'children'), { }));
}
render() {
const child = this.renderChildren();
return (
<App {...this.props}>
{child}
</App>
);
}
}
/**
* Root Loader component to load esri api
*/
class LoaderComponent extends React.Component {
constructor(props) {
super(props);
this.state = { loaded: false };
}
/**
* Callback fired when arc GIS api is loaded
* Now load the requirejs modules using dojorequire
*/
esriReady() {
dojoRequire(['esri/Map', 'esri/views/MapView'], (Map, MapView) => {
this.setState({ Map, MapView, loaded: true });
});
}
render() {
const options = {
url: 'https://js.arcgis.com/4.3/',
};
return (
<div>
<EsriLoader options={options} ready={this.esriReady.bind(this)} />
<AppWrapper {...this.state}>
<Route exact path="/home" component={Home} />
</AppWrapper>
</div>
);
}
};
const Routes = (props) => (
<Router {...props}>
<Route exact path="/" component={LoaderComponent} />
</Router>
);
export default Routes;
App and home components are simple div tags that renders <div>Hello world App</div> and <div>Hello world Home</div>
The App component renders perfectly, but when I navigate to http://localhost:3000/home component I see an empty page.
What I would like to do is
When the user launched the app the user should be redirected to /home and I would like to define two additional routes for App Component
<Route exact path="/a" component={A} />
<Route exact path="/b" component={B} />
Currently I am not able to redirect to /home on app load and not able to define nested routes for App Component.
NOTE: This above code was working fine for react-router version 3.x. To redirect on page load I would use IndexRedirect.
I already had a look at this and this question and I tried all possible solutions in those questions but none is working.
I would like to have all the route handling in routes.js file.
You could achieve such routing with Switch and Redirect:
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import {LoaderComponent, AppWrapper , Home, A, B} from './mycomponents';
const routes = (
<LoaderComponent>
<AppWrapper>
<Switch>
<Route exact path='/' render={() => <Redirect to='/home' />} />
<Route exact path='/home' component={Home} />
<Route exact path='/a' component={A} />
<Route exact path='/b' component={B} />
</Switch>
</AppWrapper>
</LoaderComponent>
);
export default routes;
And use the routes.js file something like this:
import React from 'react';
import {render} from 'react-dom';
import {Router} from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import routes from './routes';
const history = createHistory();
const App = () =>
<Router history={history}>
{routes}
</Router>;
render(<App />, document.getElementById('root'));
Hey I have implemented react-router-v4, for a simple sample project. here is the github link : How to Implement the react-router-v4. please go through it. very simple.
to run : clone it and hit npm install. hope this will help to you.

Categories