So I have a sidebar, and when I click on one of the items, it should scroll to div with a certain name. It worked before, but I decided to add 'active' class to the item clicked to change its color, and it stopped scrolling to divs.
Sidebar.jsx file:
import React, { useState} from 'react';
import './Sidebar.scss';
import { SlidebarData } from "./SlidebarData";
import spike from '../../assets/spike_pic.jpg';
const Sidebar = () => {
const [sideBar, setSidebar] = useState(false);
const [selectedLink, setSelectedLink] = useState("");
return (
<div className="sidebar">
<span className="btn" onClick={() => setSidebar(!sideBar)}>Menu</span>
<div className="profile">
<img src={spike}/>
<span>Alim Budaev</span>
<span>Available for work</span>
</div>
<ul className="sidebarlist" id={sideBar ? "hidden" : ""}>
{SlidebarData.map((val,key) =>{
return (
<li
className={`row ${selectedLink === val.link ? "active" : ""}`}
id={val.link}
key={key}
onClick={()=> {
setSelectedLink(val.link);
document.getElementById(val.link).scrollIntoView();
}}>
{""}
<div>
{val.title}
</div>
</li>
);
})}
</ul>
</div>
);
}
export default Sidebar;
As you see, I have a setState hook for selectedlink, which adds active class, but scrollIntoView doesn't work because of it, and I can't figure out why.
SidebarData.jsx, where I get links from:
export const SlidebarData = [
{
title: "Home",
link: "home"
},
{
title: "About",
link: "about"
},
{
title: "Services",
link: "services"
},
{
title: "Contact",
link: "contact"
}
]
Related
I started to learn to code recently and to create my portfolio. I am working on the header and I would like to change the text color header link tag when it is only clicked once.
When I clicked the link, the text color changed to red and when I clicked the link now but when I click another link, the previous link is still red.
I would like to change the text color back from red to gray when I click another.
Example:- OK - home about work skill contact NO - home about work skill contact
Header.jsx
import React, { useState } from "react";
import { Link as ScrollLink } from "react-scroll";
const Header = (props) => {
const { headerPage } = props;
const [onClickChangeColor, setOnClickChangeColor] = useState(false);
const redText = () => {
setOnClickChangeColor(!onClickChangeColor);
};
return (
<div class="mr-8 cursor-pointer">
<ScrollLink
className={onClickChangeColor ? "text-[#FF5757]" : ""}
onClick={redText}
to={headerPage}
smooth={true}
duration={500}
>
{headerPage}
</ScrollLink>
</div>
);
};
export default Header;
HeaderLayout.jsx
import React from "react";
import Header from "./Header";
const HeaderLayout = () => {
const headerPages = ["home", "about", "work", "skill", "contact"];
return (
<div class="sticky top-0 flex justify-end h-20 text-md pt-10 mr-10 text-center bg-[#292929]">
{headerPages.map((headerPage) => (
<Header headerPage={headerPage}>{headerPage}</Header>
))}
<div
className="resume"
class="w-24 h-8 text-[#FF5757] border border-[#FF5757] rounded-md"
>
<a
href="https://drive.google.com/file/d/usp=sharing"
class="block"
>
resume
</a>
</div>
</div>
);
};
export default HeaderLayout;
I am using React and Tailwind. English is my second language and I hope everyone understands what I want to do. Thank you in advance.
change the color handling state to parent (Header Layout)
const HeaderLayout = () => {
const headerPages = ["home", "about", "work", "skill", "contact"];
const [selectedHeader, changeSelectedHeader] = useState("");
return (
<div class="sticky top-0 flex justify-end h-20 text-md pt-10 mr-10 text-center bg-[#292929]">
{headerPages.map((headerPage) => (
<Header
headerPage={headerPage}
changeSelectedHeader={changeSelectedHeader}
selectedHeader={selectedHeader}
>
{headerPage}
</Header>
))}
then, make the child like this
import React from "react";
import { Link as ScrollLink } from "react-scroll";
const Header = (props) => {
const { headerPage, changeSelectedHeader, selectedHeader } = props;
const redText = () => {
changeSelectedHeader(headerPage);
};
return (
<div class="mr-8 cursor-pointer">
<ScrollLink
className={headerPage === selectedHeader ? "text-[#FF5757]" : ""}
onClick={redText}
to={headerPage}
smooth={true}
duration={500}
>
{headerPage}
</ScrollLink>
</div>
);
};
export default Header;
You can track the selected item index in the HeaderLayout component and then use it to decide the header item color depending on that.
Add another state to maintain the selected header item state in HeaderLayout.
const [selectedIndex, setSelectedIndex] = useState(-1);
Provide the headerIndex, selectedIndex, and setSelectedIndex as props to the Header compoenent.
{headerPages.map((headerPage, headerIndex) => (
<Header
headerPage={headerPage}
setSelectedIndex={setSelectedIndex}
selectedIndex={selectedIndex}
headerIndex={headerIndex}
>
{headerPage}
</Header>
))}
In the Header component get the props and set the header item CSS as below.
const { headerPage, selectedIndex, setSelectedIndex, headerIndex } = props;
...
...
<ScrollLink
className={headerIndex === selectedIndex ? "text-[#FF5757]" : ""}
onClick={() => setSelectedIndex(headerIndex)}
to={headerPage}
smooth={true}
duration={500}
>
Working Demo
I have a function that triggers onClick which adds borders to the clicked element.
Here is the code in the component:
import { useEffect, useState } from 'react';
import Link from 'next/link';
import Logo from '../../components/logo.svg';
import React from 'react';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
const {
publicRuntimeConfig: { domain },
} = getConfig();
export default function MediaNav() {
// If router equals link in list, show blue border
const router = useRouter();
const menu = ['Home', 'FAQs', 'Contact Us', 'Social Media'];
const [selectedPage, setPage] = useState({
borderColor: '',
});
const handleLinkClick = e => {
setPage({
borderStyle: '3px solid #005ba9',
});
e.target.style.borderLeft = selectedPage.borderStyle;
e.target.style.borderRight = selectedPage.borderStyle;
};
return (
<nav>
<div>
<Link href={`${domain}`}>
<a>
<Logo />
</a>
</Link>
</div>
<ul
>
<div>
<ul>
<li
>
All Sites
</li>
</ul>
<ul
>
{menu.map((item, i) => {
return (
<li key={i}>
<Link href={item === 'Home' ? '/subdomain/link' : `/subdomain/${item}`.replace(/\s+/g, '').toLowerCase()}>
<a onClick={handleLinkClick}>
{item}
</a>
</Link>
</li>
);
})}
</ul>
) : null}
</div>
</ul>
</nav>
);
}
At the moment, when the element in the link list is clicked, the blue border is being applied, however, if I click another link, I wanted the previously clicked element link to be removed its borders.
As this is NextJs and I have a Link tag wrapping up the link element, loading is not occurring, therefore I don't know how to make a difference between previously clicked element and currently clicked element.
Any idea how to remove the borders to already clicked link when next link is clicked?
I think a better approach to this problem would be having a state to save currentPage user visiting and depending on currentPage state giving a style to a element.
import { useEffect, useState } from 'react';
import Link from 'next/link';
import Logo from '../../components/logo.svg';
import React from 'react';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
const {
publicRuntimeConfig: { domain },
} = getConfig();
export default function MediaNav() {
// If router equals link in list, show blue border
const router = useRouter();
const menu = ['Home', 'FAQs', 'Contact Us', 'Social Media'];
const [currentPage, setCurrentPage] = useState('')
const handleLinkClick = pageName => {
setCurrentPage(pageName);
};
return (
<nav>
<div>
<Link href={`${domain}`}>
<a>
<Logo />
</a>
</Link>
</div>
<ul
>
<div>
<ul>
<li
>
All Sites
</li>
</ul>
<ul>
{menu.map((item, i) => {
return (
<li key={i}>
<Link href={item === 'Home' ? '/subdomain/link' : `/subdomain/${item}`.replace(/\s+/g, '').toLowerCase()}>
<a onClick={() => handleLinkClick(item)} style={{ border: currentPage === item ? '3px solid #005ba9': 'initial' }}>
{item}
</a>
</Link>
</li>
);
})}
</ul>
</div>
</ul>
</nav>
);
}
I think instead of adding a style on a target element, you can try adding a class, let's say highlight on the element.
highlight class would look like -
.highlight {
border-left: '3px solid #005ba9',
border-right: '3px solid #005ba9'
}
So only the elements which have this class would show the border styles applied. Since the components would re-render on state changes, make sure you are applying the highlight class on the link in map function logic. This would ensure other elements won't have this class and this would solve the problem.
PS: Removing of the previously applied styles would be tedious. I think the above solution would work without much hassle and it would work great.
I'm trying to get the Menu (from #szhsin/react-menu module) element buttons to show up to the right of the previous generated item, however I'm a bit lost as to how to get it to do so. Everything results in the element showing below previous.
import React from 'react';
import {
Menu,
MenuItem,
MenuButton,
SubMenu
} from '#szhsin/react-menu';
import '#szhsin/react-menu/dist/index.css'
class TopMenuDropdown extends React.Component {
constructor(props) {
super(props);
}
render () {
return (
<div>
{this.props.TMPMenuTestCategory.map (({name,items},i) =>
{
return <Menu
align={'end'}
key={i}
menuButton={<MenuButton>{name}</MenuButton>}
reposition={'initial'}
>
{items.map((item,j) =>
{
console.log(item,j);
return <MenuItem key={j}>{item}</MenuItem>
}
)}
</Menu>
} )}
</div>
)
}
}
I was looking through the documentation on https://szhsin.github.io/react-menu/docs , however, me trying the following has had no effect:
Assigning the display:'inline' or 'flex' the <Menu> or to a <div><Menu> as I attempted to give each menu it's own div when generated.
Wrapping each generated menu in a <span>
Fiddling with the Menu item's props like 'align' , 'position' , and 'reposition' (though I'm guessing Reposition needs an additional RepositionFlag to work if I understand it correctly)
Here's the snippet of index.JS it is part of
const basicMenuArray = [
{ name: 'ProTIS', items: [ 'Login', 'Exit' ] },
{ name: 'Project', items: [ 'Open', 'Info' ] },
]
class App extends React.Component {
state={
language:'sq'
}
render () {
return (
<div >
<div style={{display:'flex', width:'75%', float:'left' }}>
<span> Temp Text </span>
</div>
<div style={{display:'flex', width:'25%'}}>
<span style={{marginLeft:'auto'}}>
<DataComboBox
dropdownOptions={languages}
value={this.state.language}
valueField='language_code'
textField='language_full_name'
onChange={(value) => alert(JSON.stringify(value))}
/>
</span>
</div>
<div>
<TopMenuDropdown TMPMenuTestCategory={basicMenuArray} />
</div>
</div>
);
}
}
So I ended up realizing something this morning, as I'm learning ReactJS still, and my brain did not process the things properly.
I changed the initial
<div>
to
<div style={{display:'flex'}}>
and added a style={{display:'flex', float:'left'}} to the <Menu> which generates the button.
the final code snippet looks like this for anyone still learning like I am :)
return (
<div style={{display:'flex'}}>
{this.props.TMPMenuTestCategory.map (({name,items},i) =>
{
return <Menu
style={{display:'flex', float:'left'}}
key={i}
menuButton={<MenuButton>{name}</MenuButton>}
>
{items.map((item,j) =>
{
console.log(item,j);
return <MenuItem key={j}>{item}</MenuItem>
}
)}
</Menu>
} )}
</div>
)
Im new to React.
Im building and app where one of my components need to have a dynamic background image.
i have the menu-item component where it gets 2 props one of them is imgName which hold the the name like shoes.jpg.
for some reason i cant get it to be the background image.
here some of the code i have wrote
main-menu component
import React from 'react';
import MenuItem from '../menu-item/menu-item.component'
import './main-menu.style.scss'
class MainMenu extends React.Component {
constructor() {
super()
this.state = {
sections: [{
title: 'pants',
imgName: 'pants.jpg',
id: 1
},
{
title: 'shirts',
imgName: 'shirts.jpg',
id: 2
},
{
title: 'hats',
imgName: 'hats.jpg',
id: 14
},
{
title: 'jackets',
imgName: 'jackets.jpg',
id: 12
},
{
title: 'shoes',
imgName: 'shoes.jpg',
id: 6
}
]
}
}
render() {
return (
<div className="main-menu">
{this.state.sections.map(({ title, id, imgName }) => {
return (
<MenuItem imgName={imgName} title={title} key={id} />
)
})}
</div>
)
}
}
export default MainMenu
menu-item component
import React from 'react';
import './menu-item.styles.scss'
const MenuItem = ({ title,imgName }) => (
<div style={{backgroundImage:`url(../../../public/assets//'${imgName}')`}} className="menu-item">
<div className="content">
<h1 className="title">{title}</h1>
<span>buy now</span>
</div>
</div>
)
export default MenuItem;
You can try it:
<div style={{backgroundImage:`url(require(../../../public/assets//'${imgName}'))`}} className="menu-item">
<div className="content">
<h1 className="title">{title}</h1>
<span>buy now</span>
</div>
</div>
I have the following code in my component, where A nad B are my other components and SomeComponent is where I am rendering A and B along with the TabExampleSecondaryPointing component.
import { Tab } from 'semantic-ui-react';
const panes = [
{ menuItem: 'A', render: () => <Tab.Pane attached={false}> <A/> </Tab.Pane> },
{ menuItem: 'B', render: () => <Tab.Pane attached={false} > <B/> </Tab.Pane> },
]
const TabExampleSecondaryPointing = () => (
<Tab menu={{ secondary: true, pointing: true }} panes={panes} />
)
class SomeComponent extends Component {
render() {
return (
<div>
<TabExampleSecondaryPointing />
</div>
);
}
}
What I want to do is when I click some button inside of component A (which is currently active in A Tab) the current or Active Tab should switch to B Tab. I am using Tabs component of Semantic UI for React. Any help would be much appreciated. Thanks.
#Vibhor in the interest of someone else landing on this answer, and perhaps helping you to improve your solution, I would encourage you to take a look at the controlled examples for Tabs on the SUIR documentation.
What you have proposed and implemented as your solution is definitely a workaround. You are using the DOM to simulate a click event to change the auto controlled state of that component. What you want to do is directly control that state yourself. Out of the box, many SUIR components are handling the state themselves.
I put together a CodeSandbox example for you here showing how this would work with an internal component state extending upon the example in the SUIR docs:
https://codesandbox.io/s/k9ozm3w5n7
import React, { Component } from "react";
import { render } from "react-dom";
import { Button, Container, Tab } from "semantic-ui-react";
class TabExampleActiveIndex extends Component {
state = { activeIndex: 1 };
handleRangeChange = e => this.setState({ activeIndex: e.target.value });
handleTabChange = (e, { activeIndex }) => this.setState({ activeIndex });
render() {
const { activeIndex } = this.state;
const panes = [
{
menuItem: "Tab 1",
render: () => (
<Tab.Pane>
Tab 1 Content{" "}
<Button
content="Tab 2"
onClick={this.handleRangeChange}
value={1}
/>
</Tab.Pane>
)
},
{
menuItem: "Tab 2",
render: () => (
<Tab.Pane>
Tab 2 Content{" "}
<Button
content="Tab 3"
onClick={this.handleRangeChange}
value={2}
/>
</Tab.Pane>
)
},
{
menuItem: "Tab 3",
render: () => (
<Tab.Pane>
Tab 3 Content{" "}
<Button
content="Tab 1"
onClick={this.handleRangeChange}
value={0}
/>
</Tab.Pane>
)
}
];
return (
<div>
<div>activeIndex: {activeIndex}</div>
<input
type="range"
max="2"
value={activeIndex}
onChange={this.handleRangeChange}
/>
<Tab
panes={panes}
activeIndex={activeIndex}
onTabChange={this.handleTabChange}
/>
</div>
);
}
}
export default TabExampleActiveIndex;
(<any>$('.menu .item')).tab('change tab', 'tab-name');