React-router activeClassName not working as expected - javascript

For some reason, when I load/refresh the page in my app, the correct link is shown as active. When I click on a different link, it works as expected and becomes active, however the original link is also showing up as active.
UPDATE: I've just realised that when I click anywhere outside the menu bar, the active link loses its active status aswell, but the original link remains active. Essentially, when I click elsewhere, the menu returns to the example given in the first screenshot, even though the route URL is different.
Perhaps easier to demonstrate with screenshots:
This is shown on page load/refresh - as expected
But click on another link, and both of them now show as active
Click on another one, and the active link changes, but the original one is still showing as active as well
Here's my code:
One of the link elements (they are all identical, apart from SVG code and labels):
const AnnouncementLink = (props) => {
return(
<Link to="/announcements"
className={styles.assignmentLinkHolder}
activeClassName={styles.activeLinkHolder}
onClick={()=>props.hideSlideOver()}>
<span className={styles.iconHolder}>
<svg>
//Lots of SVG code here!
</svg>
<span className={styles.label}>
Announcements
</span>
</span>
</Link>
)
}
The menu element in full (not including some of the variable declarations which aren't relevant):
const photo = require('../../images/profilePics/blankface.jpg');
const SideMenu = (props) => {
//VARIABLE DECLARATIONS...
return (
<div className={styles.sideMenu}>
<img src={photo} className={styles.profilePic} />
<div className={styles.menuItem}>
<DashboardLink hideSlideOver={props.hideSlideOver} />
<CoursesLink hideSlideOver={props.hideSlideOver} />
<AssignmentsLink hideSlideOver={props.hideSlideOver}
badge={totalAssignments} />
<UsersLink hideSlideOver={props.hideSlideOver} />
<AnnouncementsLink hideSlideOver={props.hideSlideOver} />
<ReportsLink hideSlideOver={props.hideSlideOver} />
<DiscussionsLink hideSlideOver={props.hideSlideOver} />
</div>
</div>
)
}
And the React-router parent:
const Admin = () => {
return (
<Provider store={createStoreWithMiddleware(rootReducer)}>
<Router history={browserHistory}>
<Route path="/" component={Academy}>
<IndexRedirect to="/dashboard" />
<Route path="/dashboard" component={Dashboard} />
<Route path="/courses" component={CoursesMenu} />
<Route path="/assignments" component={AssignmentsMenu} />
<Route path="/users" component={UsersMenu} />
<Route path="/announcements" component={AnnouncementsMenu} />
</Route>
</Router>
</Provider>
)
}

OK, seem to have resolved it - not sure if this is a proper solution or just a workaround, but it seems to have done the trick.
The answer lies in the <SideMenu> component. By giving it a prop of path and linking this to the changing URL, it rerenders the component each time the URL changes. Also by removing <IndexRedirect> as suggested by oklas and changing it to <Route to='/'>, it prevents the active class from sticking on the <DashBoard> link.
Here's the code - this is from a section of the app that wasn't referenced above - the parent of <SideMenu>
<div className={styles.container}>
<SideMenu path={this.props.children.props.route.path} /> { //This 'path' property solves the problem by rerendering the SideMenu component every time the path changes }
<ViewPort>
{this.props.children}
</ViewPort>
</div>

Related

Page is rendering but not components although everything compiles and styles can be added outside the component

So here is a snippet of code from my App.js,
return (
<div className="app">
<Router>
{!user ? (
<LoginScreen />
) : (
<Switch>
<Route path='./profile'>
<ProfileScreen />
</Route>
<Route exact path="/">
<HomeScreen />
</Route>
</Switch>
)}
</Router>
</div>
Now when I click on the profile button, it takes me to a blank profile page and there are no errors, and everything compiles. Here is the ProfileScreen page code,
import React from 'react'
import './ProfileScreen.css'
function ProfileScreen() {
return (
<div className='profileScreen'>
<h1>
this is the profile screen
</h1>
</div>
)
}
console.log("hello")
export default ProfileScreen
Now the issue here is that every time I refresh the page the console.log("hello") (a test) shows up in developer tools! It also shows up in the main page before I am taken to the profile page. Also in the css file, I can change the entire background color using
* {
background-color:black;
}
So something is clearly working as I can change the background of the profile page but whenever I target the profileScreen class nothing shows up and my h1 never shows up even without styling when there should be text showing up. I am very new to reactJS and react-router-dom so I would appreciate any help! thank you.
I'm certain your profile path is incorrect. AFAIK react-router-dom v5 doesn't use relative path routing, it uses absolute path routing, so "./profile" is an invalid path. Update it to be "/profile".
<Switch>
<Route path="/profile">
<ProfileScreen />
</Route>
<Route exact path="/">
<HomeScreen />
</Route>
</Switch>

How do I change the route as I scroll?

I'm making my portfolio with fullpage.js and I wanted to add a route every time I get to the next element as I scroll. For example: when I open the page I get the<Home /> element in that section I want to put the router /#home when scrolling to the 2nd element <About /> the router /#about is placed, and so on, as I do this?
const Fullpagescroll = () =>{
return (
<>
<Header />
<ReactFullpage
scrollingSpeed = {1150}
navigation
render={() => {
return (
<>
<div className='section'>
<Home />
</div>
<div className='section'>
<About />
</div>
<div className='section'>
<Project />
</div>
<div className='section'>
<Contact />
</div>
</>
);
}}
/>
</>
);
}
Example
<Router>
<div className='section' >
<Route path='/#home'>
<Home />
</Route>
</div>
<div className='section'>
<Route path='/#about'>
<About />
</Route>
</div>
<div className='section'>
<Route path='/#project'>
<Project />
</Route>
</div>
<div className='section'>
<Route path='/#contact'>
<Contact />
</Route>
</div>
</Router>
Just use the anchors option as detailed on the the fullpage.js documentation:
anchors: (default []) Defines the anchor links (#example) to be shown on the URL for each section. Anchors value should be unique. The position of the anchors in the array will define to which sections the anchor is applied. (second position for second section and so on). Using anchors forward and backward navigation will also be possible through the browser. This option also allows users to bookmark a specific section or slide. Be careful! anchors can not have the same value as any ID element on the site (or NAME element for IE). Now anchors can be defined directly in the HTML structure by using the attribute data-anchor as explained here.
Alternatively you can also use the attribute data-anchor on each of your sections.
You can see examples of this on most of the examples online like this one as well as on the ones provided on the github repository.

routing within an app using react router to move to another page

I am trying to use router in my app
so I used react-router-dom, but I am facing issues,
researched and found this link but still not helping me.
Invariant failed: You should not use <Route> outside a <Router>
can you tell me how to use route and link
i need to redirect to another page.
providing my code snippet and sandbox below.
https://codesandbox.io/s/still-smoke-uf731
let Channel = ({ channelName, channelString, onClick, active }) => (
<div onClick={onClick} className=" col-lg-2 col-md-4 col-sm-6 ">
<div>router</div>
<Router>
<Link to={"/here"}> here</Link>
<Switch>
<Route path="/auth" />
<Route path="/" />
</Switch>
</Router>
<div
className="channel-button"
style={{
backgroundColor: active === channelString ? "orange" : ""
}}
>
<p>{channelName}</p>
</div>
</div>
);
Use exact as an attribute in your home route like the following code.
<Router>
<Link to={"/here"}> here</Link>
<Switch>
<Route exact path="/" />
<Route path="/auth" />
</Switch>
</Router>
I checked your sandbox. Looks like a good start, but you messed some things up.
Here is my fork of your sandbox: https://codesandbox.io/embed/staging-fast-rr5k9
First, don't put react components in the containers, put them in the components folder and import them.
What was going on was, that you had brand new <Router> for every page you had. So I pulled the Router out. Its also not imported correctly. It should be
import { BrowserRouter as Router } from "react-router-dom";
So you pretty much need something like this
<div>
<Link to={"/bbc-news"}>BBC</Link>
</div>
<div>
<Link to={"/cnbc"}>CNBC</Link>
</div>
<Switch>
<Route
key={"fbbc-news"}
path="/bbc-news"
render={p => <Channel channelName="BBC" channelString="bbc-news" />}
/>
<Route
key={"cnbc"}
path="/cnbc"
render={p => <Channel channelName="CNBC" channelString="cnbc" />}
/>
</Switch>
</Router>
Where Channel component renders whats inside the channel. the key in Route is important, because it makes React properly trigger componentDidMount, which calls the thunk action which fetches (that one is perfect).
Then to access the results from fetch, which you have placed in Redux =>
const mapStateToProps = state => ({ json: state.json });
You don't need a lot of the things you had, so I have removed them, like the onClick, which was trying to do react routers job
You can try this:
import Stats from './containers/stats';
<Route
exact={true}
path="/"
component={Stats}
key="Mykey"
/>

How to use routes in two different components - ReactJS

I am creating an application using ReactJS. I am using react router v4 from react-router-dom.
I have written routes in index.js file.
<BrowserRouter>
<Switch>
<Route exact path="/" component={Login} />
<Route exact path='/dashboard' component={Viewport} />
</Switch>
</BrowserRouter>
Rest of the application in Viewport.js file.
return (
<div className="">
<Sidebar navigation={this.viewport} />
<HeaderBanner user={this.props.user} />
<div className="center-panel">
//todo
//Can I use router here?
</div>
</div>
)
After user login's, I am rendering Viewport which contains Sidebar and header bar by default. Based on the item click in the sidebar navigation, I need to render components dynamically. As of now, if I write anything in the place of todo, it renders only that component for the complete browser window.
Is there any way to use routers in multiple places of the application? If yes, how can I implement it? If no, what's the best solution?
As far as I have seen, routers will be stacked at one place in the application.
Thanks in advance.
I followed a tutorial on youtube recently which was very useful
So I took some of it and applied it to your setup
<BrowserRouter>
<div>
<Route exact path="/" component={Login} />
<Route exact path='/dashboard' component={Viewport} />
</div>
</BrowserRouter>
import { NavLink, Route } from 'react-router-dom';
class Viewport extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div className="Side-bar">
<NavLink
activeClassName="active"
to={`${this.props.match.url}/sub-page-name-1`}>Sub Page 1</NavLink>
<NavLink
activeClassName="active"
to={`${this.props.match.url}/sub-page-name-2`}>Sub Page 2</NavLink>
<NavLink
activeClassName="active"
to={`${this.props.match.url}/sub-page-name-3`}>Sub Page 3</NavLink>
</div>
<HeaderBanner user={this.props.user} />
<div className="center-panel">
<Route path={`${this.props.match.url}/sub-page-name-1`} component={SubPagePanel1} />
<Route path={`${this.props.match.url}/sub-page-name-2`} component={SubPagePanel2} />
<Route path={`${this.props.match.url}/sub-page-name-3`} component={SubPagePanel3} />
</div>
</div>
)
}
}
I removed Switch as well because I didn't use it for my sub pages... :-S
Update: Have created a repo showing a working example of sub page content
https://github.com/PocketNinjaDesign/so-sub-routes-answer
Yes you can use <Routes> in as many places as you want. <Router> components are the ones you can only use once.

React Router Link Not Working After Render in IE

I have run into an issue where React Router's NavLink is not working upon the initial render of a dashboard screen, after a successful login. After trying many different things I am posting here. You probably won't know why either but its worth a shot.
An example layout of the dashboard is as follows:
<div>
<nav>
<NavLink>Link 1</NavLink>
<NavLink>Link 2</NavLink>
<NavLink>Link 3</NavLink>
<NavLink>Link 4</NavLink>
</nav>
<div>
<!-- CONTENT -->
</div>
</div>
Upon initial render Link 2 will be unresponsive, while Link 1, 3, and 4 work fine. Clicking Link 3 for example will render new elements in the content section and then Link 2 will work.
I have tried even changing the NavLinks to anchor tags and adding my own click handler, but no matter what I try the second Link will not work until some mysterious event takes place.
Any ideas?
Edit* Add routes for #arracso
Authenticated Route:
<Switch>
<Route path="/route-1" component={SomeComponent} />
<Route path="/*" component={Dashboard} />
</Switch>
Dashboard:
<Row>
{navigationElement}
<Column>
<Switch>
<Route path="/1" component={A} />
<Route exact path="/2" component={B} />
<Route path="/2/1" component={C} />
<Route path="/2/1" component={D} />
</Switch>
</Column>
</Row>

Categories

Resources