I was using Link to navigate to new page, now I made one page of all components and it's not doing anything on click.
import React, { useState } from 'react'
import cn from 'classnames'
// import Link from 'next/link'
import { Link } from "react-scroll"
import Logo from '../Logo/Logo'
import styles from './Layout.module.scss'
interface ILayoutProps {
children: React.ReactNode
}
export default function Layout({ children }: ILayoutProps) {
const [activeTab, setActiveTab] = useState('Home')
const navigation = ['#Home', '#About', '#Portfolio', '#Contact']
console.log(activeTab);
return (
<div>
<nav className={styles.navContainer}>
<Link to={'/#Home'}>
<Logo />
</Link>
<ul className={styles.navItems}>
{navigation.map((nav, index) => {
return (
<li key={index}>
<Link
to={`/${nav === '#Home' ? '/' : nav}`}
className={cn(styles.linkItem, {
[styles.activeTab]: activeTab === nav
})}
onClick={() => {
setActiveTab(nav)
console.log(nav)
}}
spy={true}
smooth={true}
offset={50}
duration={500}
>
{nav.slice(1)}
</Link>
</li>
)
})}
</ul>
<a className={styles.button} href='assets/Stas_Gavrilov_resume.txt' download>Resume</a>
</nav>
<main>{children}</main>
</div>
)
}
I follow up with the docs on react-scroll but it did not helped to solve my issue :(
It's saying it can't target the section element:
react_devtools_backend.js:4012 target Element not found
You need to remove the / on the to prop in the Link component since the id of the element you want to scroll to has not the id /#Home but #Home.
<Link
to={`${nav === "#Home" ? "/" : nav}`} // here
...
>
Instead of
<Link
to={`/${nav === "#Home" ? "/" : nav}`}
...
>
Note that the id needs to match so the elements you want to scroll to must have the exact id.
Since your list of ids is
const navigation = ["#Home", "#About", "#Portfolio", "#Contact"];
The id of the elements need to contain the #
<>
<section id="#Home">Home</section>
<section id="#About">About</section>
<section id="#Portfolio">Portfolio</section>
<section id="#Contact">Contact</section>
</>
Related
In my nextjs-app I have a Navbar with some navitems:
Navbar.tsx:
const Navbar = ({ navitems }) => {
return (
<div>
{navitems?.map((navitem, idx) => (
<NavItem key={idx} navitem={navitem} />
))}
</div>
)
}
export default Navbar
NavItem.tsx:
import Link from "next/link"
import { useRouter } from "next/router"
const NavItem = ({navitem}) => {
const router = useRouter()
return (
<div>
<Link href={"/" + navitem.url.slug}
className={`${ router.query.slug === navitem?.url?.slug ? "active " : ""}`}>
{navitem.title}
</Link>
</div>
)
}
export default NavItem
So far so good. When I'm the route /about the menu item has the active-class.
How can I add the active class when I have dynamic routes like for example /about/employees - so that the Navitem "about" still has the active class?
How can I achieve that?
I'm trying to add and remove a class when clicking on an item of my header, but I struggle to do it and I don't know how to map the rendered items in the header component.
Here's the first part of the code with a function that works for routing and window.location.
I'm able to add the class but it gets added to each element clicked and it gets removed only when I click again on it.
import React, { useState } from 'react';
const Link = ({ href, children }) => {
const [activeItem, setActiveItem] = useState(false);
const onClick = (event) => {
if (event.metaKey || event.ctrl) {
return;
}
event.preventDefault();
window.history.pushState({}, '', href);
const navEvent = new PopStateEvent('popstate');
window.dispatchEvent(navEvent);
setActiveItem(!activeItem);
};
return (
<a
onClick={onClick}
className={`item ${activeItem ? 'active' : ''}`}
href={href}
>
{children}
</a>
);
};
export default Link;
Here's my header element instead:
import React from 'react';
import Link from './Link';
import Logo from './Logo';
const Header = () => {
return (
<div className="ui secondary pointing menu">
<Link href="/">
<Logo />
</Link>
<div className="pointing right menu">
<Link href="/services">services</Link>
<Link href="/works">works</Link>
<Link href="/contacts">contacts</Link>
</div>
</div>
);
};
export default Header;
You need to make your link components aware of each other by lifting the state to your header component. Then you pass you tell your link components which link is currently selected by passing it as a prop and you also need to give them the ability to change which link is currently selected:
import React from 'react';
import Link from './Link';
import Logo from './Logo';
const Link = ({ href, children, isActive, handleClick }) => {
const onClick = (event) => {
if (event.metaKey || event.ctrl) {
return;
}
event.preventDefault();
window.history.pushState({}, '', href);
const navEvent = new PopStateEvent('popstate');
window.dispatchEvent(navEvent);
handleClick();
};
return (
<a
onClick={onClick}
className={`item ${isActive ? 'active' : ''}`}
href={href}
>
{children}
</a>
);
};
export default Link;
const Header = () => {
const [activeLink, setActiveLink] = useState(0)
return (
<div className="ui secondary pointing menu">
<Link
href="/"
isActive={activeLink === 0}
handleClick={() => setActiveLink(0)}
>
<Logo />
</Link>
<div className="pointing right menu">
<Link
href="/services"
isActive={activeLink === 1}
handleClick={() => setActiveLink(1)}
>
services
</Link>
<Link
href="/works"
isActive={activeLink === 2}
handleClick={() => setActiveLink(2)}
>
works
</Link>
<Link
href="/contacts"
isActive={activeLink === 3}
handleClick={() => setActiveLink(3)}
>
contacts
</Link>
</div>
</div>
);
};
export default Header;
I want my nav bar to style the page title I'm in, im using React and Tailwind CSS, for example, just make the title yellow when im on the selected path.
My logic to achieve that would be this but isn't working:
<div className={active ? "text-yellow-400" : undefined}
My rout code:
const LinkItem = ({href, path, children, ...props}) => {
const active = path === href
return (
<NextLink href={href}>
<div className={active ? "text-yellow-400" : undefined}
{...props}
>
{children}
</div>
</NextLink>
)
}
Nav bar code:
const Navbar = props => {
const {path} = props
return (
<LinkItem href="/page1" path={path}>
Page 1
</LinkItem>
)
}
Instead of undefined use either null or a empty string ""
Aswell. Use useState (not really needed in this scenario, but its always best to use in practice)
https://reactjs.org/docs/hooks-state.html
Well at the end the problem was the path variable which was undefined, and wasn't able to match href, so the condition never met.
Solution: call the path from useRouter hook with parameter .asPath, this gives me back the parameter which i stored in my path variable.
Code:
import NextLink from 'next/link'
import {useRouter} from "next/router";
const LinkItem = ({href, children, ...props}) => {
const path = useRouter().asPath
const active = path === href
return (
<NextLink href={href}>
<div className={active ? "<styles here>" : "<styles here>"}
{...props}
>
{children}
</div>
</NextLink>
)
}
Nav bar code:
const Navbar = props => {
const {path} = props
return (
<LinkItem href="/page1" path={path}>
Page 1
</LinkItem>
<LinkItem href="/page2" path={path}>
Page 2
</LinkItem>
)
}
I've created a Breadcrumb component but I'm struggling to add routing to it.
So far, the component is able to load a custom number of nodes based on how many elements we send to an array and it logs into the console the name of the node when clicked.
What it is needed is to make this breadcrumb change the url when a node is clicked.
It should contain something like this:
<Switch>
<Route path="/component0" component={Component0} />
<Route path="/component1" component={Component1} />
...
</Switch>
Is it possible to make it for a custom number of nodes?
This is the code so far:
Parent component:
import React, { useState } from 'react';
import Breadcrumbs from './Breadcrumbs';
export interface BreadcrumbProps {}
export function Breadcrumb(props: BreadcrumbProps) {
const [crumbs, setCrumbs] = useState(['Home', 'Category', 'Sub Category']);
const selected = (crumb: any) => {
console.log(crumb);
};
return (
<div>
<Breadcrumbs crumbs={crumbs} selected={selected} />
</div>
);
}
export default Breadcrumb;
Child component:
function Breadcrumbs(props: any) {
function isLast(index: number) {
return index === props.crumbs.length - 1;
}
return (
<nav className=''>
<ol className=''>
{props.crumbs.map((crumb, ci) => {
const disabled = isLast(ci) ? 'disabled' : '';
return (
<li key={ci} className=''>
<button className={`btn btn-link ${disabled}`} onClick={() => props.selected(crumb)}>
{crumb}
</button>
</li>
);
})}
</ol>
</nav>
);
}
export default Breadcrumbs;
I have a navigation component with a list containing links. I need to run a function when these are clicked in addition to linking(going to specific page). What I have so far is working except if user clicks on link to active page.
How can I modify my code so my function doesn't run and link is disable if user is already on that page?
Here is what I have:
class HeaderMenu extends Component {
navFunc = () => {
//some functionality
}
render() {
return (
<div>
<div className="sidebar">
<ul className="header">
<li onClick={this.navFunc}>
<Link href="/index">
<a>home</a>
</Link>
</li>
<li onClick={this.navFunc}>
<Link href="/about">
<a>about</a>
</Link>
</li>
<li onClick={this.navFunc}>
<Link href="/other">
<a>other</a>
</Link>
</li>
</ul>
</div>
</div>
)
}
}
You can create an ActiveLink component that will skip the push action when clicked.
This ActiveLink component is based on the example in the next.js documentation (scroll up to see it), and I have not tested it.
import { withRouter } from 'next/router'
const ActiveLink = ({ children, router, href }) => {
const active = router.pathname === href
const style = {
marginRight: 10,
color: active ? 'red' : 'black'
}
const handleClick = (e) => {
e.preventDefault()
active || router.push(href)
}
return (
<a href={href} onClick={handleClick} style={style}>
{children}
</a>
)
}
export default withRouter(ActiveLink)