React Router v4 - active link issue - css

I am having an issue with active link.
I need to create few sub Routes and keep active styling on "parent" Route. How can I achieve that?
I am using withRouter for Routing purposes.
Let say I have main Navigation with 3 "parent" Routes - /login | /register /profile.
render () {
return (
<div className='grid'>
<Route exact path='/' component={HomePage} />
<Route path='/login' component={LoginForm} />
<Route path='/register' component={RegisterForm} />
<PrivateRoute path='/profile' component={PersonalDetails} />
<PrivateRoute path='/profile/delete-account' component={DeleteAccount} />
<PrivateRoute path='/profile/payments' component={Payments} />
<PrivateRoute path='/profile/food-preferences' component={FoodPreferences} />
</div>
);
}
Inside Component which is rendering on '/profile' route there is additional navigation with links to '/profile/delete-account/', '/profile/payments', 'profile/food-preferences'.
static getProfileRoutes () {
return profileRoutes.map(route => (
<NavLink to={route.path} activeClassName='active-profile' className='profile-navigation-button' key={route.path}>
<li className='profile-navigation-label'>{route.name}</li>
</NavLink>
));
}
Unfortunately when I navigate to one of "child" routes, active styling from button in SideBar which navigates to '/profile' is lost. How can I prevent it? Fix it?
static getSideBarRoutes () {
return sideBarRoutes.map(route => (
<NavLink className='navigation-button' key={route.path} to={route.path}>
<li className='navigation-item'>
<div className={route.icon} />
{route.name}
</li>
</NavLink>)
);
}
Routing is working perfectly fine - its just problem with active class lost on Sidebar
Many thanks for your help.

For example
const navigation = (props) => {
let styleClass= "not-active-class";
if (props.location.pathname.indexOf(props.route) !== -1) {
// checking if parent route is contained in route and setting active class
styleClass= "active-class";
}
return (
<NavLink
to={props.route}
activeClassName={styleClass} >
<p>{props.route}</p>
</NavLink>
);
}

Related

My Link with href doesn't scroll even though the link changes. Nextjs

I'm working on a react with nextjs project.
I'm using Link to scroll to a specific section on the same page.
Here is one of the components that use Link:
import styles from './section1.module.scss';
import Image from 'next/image';
import Button from '#material-ui/core/Button';
import tought_process from '../../../public/thought_process.png';
import Link from 'next/link';
const Section1 = () => {
return (
<div className={styles.container}>
<div className={styles.left}>
<div className={styles.leftContainer}>
<Link href='#enews'>
<div className={styles.buttonContainer}>
<Button className={styles.buttonstyle1}>Get started</Button>
</div>
</Link>
</div>
</div>
<div className={styles.right}>
<Image
src={tought_process}
className={styles.imageStyle}
alt='how to think about organizing'
layout='responsive'
priority
/>
</div>
</div>
);
};
export default Section1;
And here i mark the element with the id:
<div {...handlers} className={styles.bigBody}>
<NavBar open={menuOpen} toggle={setMenuOpen} scrollY={scrollY} />
<SideMenu open={menuOpen} toggle={setMenuOpen} scrollY={scrollY} />
<div className={styles.sections}>
<Section1 />
<Section2 />
<Section3 id='enews' />
<Section4 />
</div>
Can't figure out what i'm doing wrong.
Multiple clickable elements are wrapping each other. Remove the button and add the anchor element.
<Link href="#enews">
<a>Get started</a>
</Link>
<Link href="#enews">
<a className={styles.buttonContainer}>
<span className={styles.buttonstyle1}>Get started</span>
</a>
</Link>
I'd recommend updating the styles so you can remove the inner span element.
I use a custom link component that does a few things (not shown); one is smooth scroll to hash routes if the browser supports smooth scrolling (not Safari).
import NextLink, { LinkProps } from "next/link";
import { HTMLProps, MouseEvent, FC } from "react";
export const Link: FC<LinkProps & HTMLProps<HTMLAnchorElement>> = ({ as, children, href, replace, scroll, shallow, passHref, ...rest}) => {
const onClick = (event: MouseEvent<HTMLAnchorElement>) => {
if (href.startsWith("#")) {
event.preventDefault();
const destination = document.getElementById(href.substring(1));
if (destination) destination.scrollIntoView({ behavior: "smooth" });
}
};
return (
<NextLink as={as} href={href} passHref={passHref} replace={replace} scroll={scroll} shallow={shallow}>
<a href={href} {...rest} onClick={onClick}>
{children}
</a>
</NextLink>
);
};
I removed new lines to condense the code block
If you went with the above approach, don't include the anchor tag since it's automatically included.
import { Link } from "./custom/path/link"
<Link href="#enews">Get started</Link>
Two points here:
As per the nextjs, passHref has to be used if a custom element is used as a child of Link tag instead of an anchor tag.
As per the same docs value of href should be '/#enews' not '#enews'

How to use Next.js <Link> prefetch for a <button>? (And avoiding a double selection while navigating with Tab key)

Accessibility best practices suggest using <button> for button elements.
Prefetching for Next.js can be done via <Link>.
However, when you combine the two and use the Tab key to navigate, it will essentially select that button twice. E.g.
<Link href="#">
<a>
This selects once
</a>
</Link>
<Link href="#">
<a>
<button>
This selects twice
</button>
</a>
</Link>
You could do something like this:
<button
onClick={() => { window.location.href "#" }
>
This only selects once
</button>
But that doesn't prefetch.
You can use router.prefetch to fetch the route before going to the page. Check this for more details
export default function Login() {
const router = useRouter()
const onClick = useCallback((e) => {
router.push('/dashboard')
}, []);
useEffect(() => {
router.prefetch("/dashboard"); // Prefetch the dashboard page
}, [])
return (
<button onClick={onClick}>Login</button>
)
}
this is for nuxt
you don't need to do that way, you can just add props and value into nuxtlink
<NuxtLink
id="home-link"
:to="localePath('/')"
exact
active-class="nav-active"
tag="button"
class="btn btn-primary"
>
Home/Any Name
</NuxtLink>
for next top answer is right
export default function Login() {
const router = useRouter()
const onClick = useCallback((e) => {
router.push('/dashboard')
}, []);
useEffect(() => {
router.prefetch("/dashboard"); // Prefetch the dashboard page
}, [])
return (
<button onClick={onClick}>Login</button>
)
}

react-helmet changing css in the head tag during runtime has lag (no css for 1 sec before it shows updated css)

This is a simplified React component that uses helmet to update the link css on runtime:
function App() {
const [brand, setBrand] = useState('nike')
return (
<div className="App">
<Helmet>
<link rel="stylesheet" href={getBrandStyle(brand)} />
</Helmet>
<div>other contents here</div>
<!-- omitted the button components that change the brand state by calling setBrand -->
</div>
);
}
I have recently just used react-helmet as a declarative way to change the head tag's child and with the code I wrote above, when switching the css there is momentary lag when the page has no css stylings and then 1 second later the updated css shows up.
Even during the initial load of the page, if I use queryParameters (code above doesn't show the query parameter approach) such as
https://localhost:3000?brandQueryParam=nike
there is 1 second wherein there is no css styling before the brand css shows up.
Can you please let me know what I am missing and how to resolve this?
This is the solution that I came up with, not sure if setTimeout is the best solution so if anyone else knows a better way, please share it.
const brands = {
nike: 'nike2022',
adidas: 'adidas2017',
fila: 'fila2020'
};
function App() {
const [brand, setBrand] = useState('nike')
const [isLoading, setIsLoading] = useState(false)
const changeBrandStyleOnClick = (brand) => {
setBrand(brand)
setIsLoading(true)
}
return (
<div className="App">
<Helmet>
<link rel="stylesheet"
onChangeClientState={(newState, addedTags, removedTags) => setTimeout(() => setIsLoading(false), 1500)}
href={getBrandStyle(brand)} />
</Helmet>
{isLoading && (
<Overlay>
<Spinner/>
</Overlay>
)}
{!isLoading && (
<>
{Object.keys(brands).filter(b => b !== brand).map(b =>
(<Button onClick={() => changeBrandStyleOnClick (b)} value={b}>
<Logo
alt="default alt name"
appearance="default"
name={b}
size="small"/>
</Button>))
}
<div>other contents here</div>
</>
)}
</div>
);
}

how to put the child content inside the parent without import on Vue JS

I want to not need to import a child component.
and Manipulation within the parent
On ReactJS is like that
`export const PrivateRoute = ({
isAuthenticated,
component: Component,
...rest
}) => (
<Route
{...rest}
component={props =>
isAuthenticated ? (
<div>
<Component {...props} />
</div>
) : (
<Redirect to="/" />
)
}
/>
);`
On vue i want do something like that
The child :
<template>
title
<test>//parent
<div>Content</div>//child
</test>
</template>
on Parent Test like that
<template lang="">
<div>
Hello
<component></component> //Content Child
</div>
</template>
how do i do, can someone help me?

Is it possible to send function from parent to hidden child component in ReactJs

I have a parent component from which I would like to send function to my child component.
ParentComponent.js
export default class LandingPage extends React.Component {
onSearchSubmit(term) {
console.log(term);
}
render() {
return (
<div>
<div className = "admin" >
<SearchBar onSubmit = {this.onSearchSubmit}
/>
</div>
....
ChildComponent.js
export default class SearchBar extends React.Component{
state = {term: ''};
onFormSubmit = event => {
event.preventDefault();
this.props.onSubmit(this.state.term);
};
render(){
return(
<div>
<div className="container">
<div className="searchBar mt-5">
<form onSubmit={this.onFormSubmit}>
<div className="form-group">
<label for="search">Image search</label>
<input
type="text"
className="form-control"
placeholder="Search..."
value = {this.state.term}
onChange={e => this.setState({term: e.target.value})}
/>
</div>
</form>
</div>
</div>
</div>
)
}
}
I'm sending function to my child component so I could get input from user using search bar back to parent component. It works fine if child component is displayed and used on parent component.
But if I would like to approach my child component in a way that I hide it from parent component with CSS:
.admin{
display: none;
}
and access it like http://localhost:3000/bar and type text in my search bar there I am getting following error:
Uncaught TypeError: _this.props.onSubmit is not a function
Is it possible to send data this way using ReactJs or is there any other way to send data to child component without displaying child component in parent?
UPDATE - WORKING SOLUTION
I added parent component for both of my pages.
I have changed structure of my app in that way.
Before my app was structured in way that my LandingPage.js was a parent to SearchBar.js.
That's why I couldn't make communication between them work in way I wanted. I was trying to hack it by hiding search bar from my landing page and trying to send data from http://localhost:3000/searchbar to http://localhost:3000/ without any luck and getting errors.
After I structured my app tp look like this:
I was able to send data between LandinPage.js and SearchBar.js.
App.js looked like this:
export default class App extends React.Component{
render(){
return(
<div>
<Route path="/" exact component={LandingPage} />
<Route path="/admin" component={Admin}/>
<Route path="/posts" component={Post} />
<Route path="/categories" component={Categories} />
<Route path="/users" component={Users} />
<Route path="/details" component={Details} />
<Route path="/profile" component={Profile} />
<Route path="/weatherapp" component={weatherApp} />
<Route path="/bar" component={SearchBar}/>
</div>
)
}
}
To make App.js as parent have changed it to look like this:
App.js
export default class App extends React.Component{
constructor(props){
super(props)
this.state = {
articalName: "Landing page"
};
}
onSearchSubmit = term => {
console.log(term);
}
render(){
return(
<div>
<Route path="/" exact component={LandingPage} />
<Route path="/admin" component={ () =>
<Admin
title={this.state.articalName}
/>}
/>
<Route path="/posts" component={Post} />
<Route path="/categories" component={Categories} />
<Route path="/users" component={Users} />
<Route path="/details" component={Details} />
<Route path="/profile" component={Profile} />
<Route path="/weatherapp" component={weatherApp} />
<Route path="/bar" component={ () =>
<SearchBar
onSubmit={this.onSearchSubmit}
/>}
/>
</div>
)
}
}
I used routes to send my data from parent to child. This example uses React Router 4. I wanted to use only ReactJs but I guess good solution would be also using Redux.
Since you do not want a parent-child relationship between both the components, how about making them as siblings and add a parent component for both of them!
With that any search made in the SearchBar component you can pass it to the new parent and from that to the earlier considered parent.

Resources