URL changes with React Router but component not rendering? - javascript

I'm setting up a React app to utilize React Router. The URL changes when I click the Volunteers header on the left, but the component does not render. How should I set this up?
I've tried to put the Routes in the SidePanel component, but I don't want the components to be rendered by React Router to be children of SidePanel, but siblings.
My App Component:
// system imports
import React from "react";
import { BrowserRouter, Route} from "react-router-dom";
// custom components
import SidePanel from "./SidePanel.js";
import VolunteerCombo from "./VolunteerCombo.js";
import RegistrantsCombo from "./RegistrantsCombo.js";
import Assignments from "./Assignments.js";
import ActionLog from "./ActionLog.js";
// css files
import "../css/App.css";
import "../css/ActivePanel.css";
import "../css/MenuPanel.css";
export class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="main_container">
<SidePanel/>
<BrowserRouter>
<Route path="/volunteers" component={VolunteerCombo}></Route>
<Route path="/registrants" component={RegistrantsCombo}></Route>
<Route path="/assignments" component={Assignments}></Route>
<Route path="/action_log" component={ActionLog}></Route>
</BrowserRouter>
</div>
);
}
}
And my SidePanel Component:
// system imports
import React from "react";
import { BrowserRouter, Route, Link } from "react-router-dom";
// custom components
// css files
import "../css/SidePanel.css";
class SidePanel extends React.Component {
constructor(props) {
super(props);
this.state = {
title: ""
};
}
render() {
return (
<div className="side_panel">
<BrowserRouter>
<h3 style={{paddingTop: "3%"}}>Chase Grainger</h3>
<p className="ui button">Log Out</p>
<div className="ui divider"></div>
<Link to="/volunteers">
<h4 className="side_button">Volunteers</h4>
</Link>
<h4 className="side_button">Registrants</h4>
<h4 className="side_button">Assignments Mode</h4>
<div className="ui divider"></div>
<h4 className="side_button">Action Log</h4>
</BrowserRouter>
</div>
);
}
}
export default SidePanel;
I expected my VolunteerCombo component to show up when I clicked Volunteers on the left side, but the component did not render although the URL changed.

First of all, you need to have one BrowserRouter. SidePanel also needs to under BrowserRouter.
So overall, you need to have one more component.
<BrowserRouter>
<Route path="/" component={Layout} />
</BrowserRouter>
in Layout.js
<div>
<SidePanel />
<Switch>
...your routes
</Switch>
</div>
And use withRouter HOC for SidePanel.

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.

Same component used in multiple routes is being remounted react-router

I created a simple react application. It has a header and three other components called welcome, feature 1 and feature 2.
index.js
import React from 'react'
import { render } from 'react-dom'
import { BrowserRouter, Route } from 'react-router-dom'
import App from './App';
render((
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
), document.getElementById('root'));
App.js
import React from 'react'
import Header from './Header'
import Main from './Main'
const App = () => (
<div>
<Header />
<Main />
</div>
)
export default App
Header.js
import React, { Component } from 'react';
export default class Header extends Component {
componentDidMount() {
APICall('/user')
}
render() {
return (
<div>I am header</div>
)
}
}
Main.js
import React, { Component } from 'react'
import { Route } from 'react-router-dom'
import Welcome from './Welcome'
import Feature1 from './Feature1'
import Feature2 from './Feature2'
export default class Main extends Component {
render() {
return (
<div>
<Route exact path="/" component={Welcome} />
<Route path="/feature1" component={Feature1} />
<Route path="/feature2" component={Feature2} />
</div>
)
}
}
welcome.js
import React, { Component } from 'react';
export default class Welcome extends Component {
render() {
return (
<div>Welcome!</div>
)
}
}
Feature1.js
import React, { Component } from 'react';
export default class Feature1 extends Component {
render() {
return (
<div>I am Feature1</div>
)
}
}
Feature2.js
import React, { Component } from 'react';
export default class Feature2 extends Component {
render() {
return (
<div>I am Feature2</div>
)
}
}
Welcome, Feature1 and Feature2 are in different routes where as Header is common in all the routes. Say I have a user and I want to show the username on the header. I will make an API call to get the username in componentDidMount() life-cycle hook of header.
Now if I change the route, I don't want the API call to be made again as the username is not going to change. And I thought that is how this was going to behave. As Header component is same in all the routes, I thought Header won't re-mount when I change the route. But that is not what is happening. It is remounting and making the API call again. How can I make sure that the API call is made only once?
I think in this case considering your Header is aware of what User is logged, i.e. App.js state passed down as props, you could use shouldComponentUpdate():
shouldComponentUpdate(nextProps, nextState) {
// see if user changed
if(nextProps.user !== nextState.user){
return true;
}
// returning false will prevent re-rendering
return false;
}
I hope this is somehow useful.
Have a good day!
change to this in index.js:-
<BrowserRouter>
<App />
</BrowserRouter>
It seems you messed up the routing then, because in your router you have only one route registered, which seems to trigger on any child route change. Also, routes should be wrapped in a Switch component.
Check out this structure
/** index.js */
import React from 'react'
import { render } from 'react-dom'
import App from './App';
render(<App />, document.getElementById('root'));
/** App.jsx */
import React from 'react'
import Header from './Header'
import Main from './Main'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
const App = () => (
<div>
<Header />
<BrowserRouter>
<Switch>
<Route exact path="/" component={Homepage} />
<Route exact path="/f1" component={Feature1} />
<Route exact path="/f2" component={Feature2} />
<Route component={NotFound} />
</Switch>
</BrowserRouter>
</div>
)
export default App

Trying to use multiple component for a single path

I'm working on a react app and I have several components I want to use on my root path. I wonder what are best practices as far as rendering then on one component and then linking that component to my root or if I could add all components to my root path.
I want to add 3 other components to root path.
This is my app.js file:
import React, { Component } from "react";
import { BrowserRouter, Route } from "react-router-dom";
import Header from "./components/Header";
import EyewearTitle from "./components/EyewearTitle";
import Buy from "./components/Buy";
import './App.css';
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Header />
<Route exact path="/" component={EyewearTitle} />
<Route exact path="/buy" component={Buy} />
</div>
</BrowserRouter>
);
}
}
export default App;
You should add all components you want to render under a single component. For example, I might use a <ShoppingScreen/> component, and on that screen, would render:
render() {
return(
<div className="shopping-screen">
<ShoppingScreenSideBar/>
<ShoppingScreenItems/>
</div>
);
}

React Component not rendering on using react router 4

I am working on a simple demo React project. I have a Home component which gets rendered when directly placed in main.js but when placed inside the Router in Routes.js, it is not rendered. Can anyone let me know what am I doing wrong here?
main.js file
import React from "react";
import {render} from "react-dom";
import {App} from "./app/App";
import Routes from "./app/Routes";
render( <Routes />,
document.getElementById("root")
)
Routes.js file
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
} from "react-router-dom";
import {App}
from "./App";
import Home from "./components/Home";
export default function Routes(props) {
console.log('Routes');
return (
<Router>
<App>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</App>
</Router>
)
}
App.js file
import React from "react";
import Header from "./components/Header";
export class App extends React.Component {
render() {
console.log("App render");
return (
<div>
<h1> Welcome to React </h1>
<Header/>
</div>
)
}
}
Header.js file
import React, {Component} from 'react';
import {NavLink} from 'react-router-dom';
export default class Header extends Component {
render() {
console.log("Header render");
return (
<div>
<NavLink to="/" exact>
Home
</NavLink>
</div>
)
}
}
Home.js file
import React, {Component} from "react";
export default class Home extends Component {
render() {
console.log("Home render");
return (
<div>
<h2>Hello World!</h2>
</div>
)
}
}
This is because you are using App component as the wrapper of whole app, and defined the Switch as the children of App component, so you need to use this.props.children inside App.
Like this:
export class App extends React.Component {
render() {
console.log("App render");
return (
<div>
<h1> Welcome to React </h1>
<Header/>
{this.props.children}
</div>
)
}
}
Consider this example to make the whole picture more clear, if you write:
<App>
<Home />
</App>
Means Home will get passed as children to App component, automatically it will not get rendered inside App, you need to put this.props.children somewhere inside App.
With react-router-v4 which you seem to be using, it is possible to have dynamic Routing which means you can add the Routes within nested components and hence apart from the solution that #MayankShukla suggested you could also keep the <Switch> and other routes within App like
export default function Routes(props) {
console.log('Routes');
return (
<Router>
<App/>
</Router>
)
}
export class App extends React.Component {
render() {
console.log("App render");
return (
<div>
<h1> Welcome to React </h1>
<Header/>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</div>
)
}
}
You could read more about the advantages of Dynamic Routing here

react router navigation in half page

I am designing a website in which the header is the same for three pages.
By default the fist page should have the following components
Header QueryList
and on click of a button present in Header the QueryList component should change to FindExpert.js.
Along with the change in Page, the URL also changes on the click of a button.
Header FindExpert
Since header is present in both the screens and I don't want to call the component again and again in every js file.So, I used ternary operator in the header.js file so that I can route in half of the page.
App.js
import React, { Component } from 'react';
import {BrowserRouter,Route,Router,Switch} from 'react-router-dom';
import {Header} from './Header.js';
import {FindExpert} from './FindExpert.js';
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<Switch>
<Route exact path="/" component={Header} />
<Route path="/findexpert" component={FindExpert} />
</Switch>
</BrowserRouter>
</div>
);
}
}
export default App;
Header.js
import React, { Component } from 'react';
import {Constants} from './constants.js';
import {QueryList} from './QueryList.js';
import {FindExpert} from './FindExpert.js';
export class Header extends React.Component{
constructor(props) {
super(props);
this.state = {
ProfileData: {},
profileImage: "profile-pic.svg",
isClicked:false
};
this.findExpertClicked = this.findExpertClicked.bind(this);
this.findExpertPage=this.findExpertPage.bind(this)
}
findExpertClicked() {
console.log("Find expert clicked");
this.setState({
isClicked:true
})
}
findExpertPage(){
this.props.history.push('/findexpert');
}
render(){
return(
<div>
<div className="col-md-12 HeaderBar">
<div className="HeaderContent">
</div>
</div>
<div className="ProfileHeader">
<div className="profileImageDiv">
<img src={this.state.profileImage} className="profileImageSrc" alt="Alternate"></img>
</div>
</div>
<div className="headerButtons">
<div className="ExBtnDiv" onClick={this.findExpertClicked}><span className="ExBtn">Find Expert</span></div>
</div>
</div>
<div>{(this.state.isClicked===false)?<div><QueryList/></div> :<div>{this.findExpertPage()}</div>}</div>
</div>
)
}
}
And in FindExpert.js, suppose I have a simple Hello world.
import React, { Component } from 'react';
import {Header} from './Header.js';
import {Constants} from './constants.js';
export class FindExpert extends React.Component{
render(){
return(
<div>
Hello world
</div>
)
}
}
Through the above code, the QueryList comes below the Header as expected but when clicked on the find expert button, the whole page changes.
Since I don't want to call header.js in both the files, is there a way to keep the header constant and change the contents below it as well as change the url when find expert button is clicked.
You have to create separate components for Header and the content to be shown on the homepage. And directly render the Header component inside App.js
This way Header component will always be rendered and only the page content would change according to the current route.
For example:
import React, { Component } from 'react';
import {BrowserRouter,Route,Router,Switch} from 'react-router-dom';
import {Header} from './Header.js';
import HomePage from './HomePage.js';
import {FindExpert} from './FindExpert.js';
class App extends Component {
render() {
return (
<div>
<Header />
<BrowserRouter>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/findexpert" component={FindExpert} />
</Switch>
</BrowserRouter>
</div>
);
}
}
export default App;

Categories