How Can I set State in stateless Function, in a nested Function? - reactjs

I know that I can't change the state in a stateless function when the function is nested, though I am only this far away to set the state in order for the page work as I would want. I want to keep this as a functional component. The issue is below I want to set the language under this function, or any other way works I know how to do this with Class component, though unless there will be 10 votes to do that would prefer to stay with functional.
function changeTounge(e) {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
//setLanguage({ iso2: "lv", speak: "Latviešu" });
}
the full code is:
import React, { useState } from "react";
import { Link } from "react-router-dom";
export function PrimaryNav() {
const [language, setLanguage] = useState({ iso2: "us", speak: "English" });
return (
<div className="primary-nav">
<ul className="navigation">
<li className="active">
<Link to="/">Home</Link>
</li>
<li className="has-child">
Opportunities
<div className="wrapper">
<div id="nav-homepages" className="nav-wrapper">
<ul>
{OpsOption("RealEstate", "Real Estate")}
{OpsOption("Vehicles", "Vehicles")}
{OpsOption("JobSearch", "Job Search")}
{OpsOption("PersonalCompany", "Personal Company")}
{OpsOption("Inves`enter code here`tInIdea", "Invest In Idea")}
</ul>
</div>
</div>
</li>
<li>
<Link to="/contact">Help & Support</Link>
</li>
<li className="has-child language">
{ActiveLanguage(language.iso2, language.speak)}
<div className="wrapper">
<div id="nav-languages" className="nav-wrapper">
<ul>
{LanguageOption("English", "us")}
{LanguageOption("British", "gb")}
{LanguageOption("Latviešu", "lv")}
{LanguageOption("Estonia", "ee")}
{LanguageOption("Lithuania", "lt")}
{LanguageOption("Russian", "ru")}
{LanguageOption("Deutch", "de")}
{LanguageOption("French", "fr")}
</ul>
</div>
</div>
</li>
</ul>
</div>
);
}
function LanguageOption(label, classLabel) {
return (
<li
onClick={changeTounge.bind(this)}
data-id={label}
data-value={classLabel}
>
<Link to="#nav-locations">
<span className={"flag-icon flag-icon-" + classLabel}></span>
{" "}
{label}
</Link>
</li>
);
}
function changeTounge(e) {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
//setLanguage({ iso2: "lv", speak: "Latviešu" });
}
function OpsOption(pageLink, label) {
return (
<li>
<Link to={"/" + pageLink}>{label}</Link>
</li>
);
}
function ActiveLanguage(iso2, activeLanguage) {
return (
<a href="#nav-languages">
<span className={"flag-icon flag-icon-" + iso2}></span> {activeLanguage}
</a>
);
}
export default PrimaryNav;

Try nesting the components inside of the main component, they'll be able to access and set its state. This is still a functional pattern here.
The other option would be to add a prop to your children components, and pass in the setLanguage function through that prop.
Also, you don't need the changeTounge.bind.this in functional react :D. In general, if you're using this at all in functional react... that's a red flag.
import React, { useState } from "react";
import { Link } from "react-router-dom";
const PrimaryNav = () => {
const [language, setLanguage] = useState({ iso2: "us", speak: "English" });
const changeTounge = (e) => {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
setLanguage({ iso2: "lv", speak: "Latviešu" });
}
const OpsOption = (pageLink, label) => {
return (
<li>
<Link to={"/" + pageLink}>{label}</Link>
</li>
);
}
const ActiveLanguage = (iso2, activeLanguage) => {
return (
<a href="#nav-languages">
<span className={"flag-icon flag-icon-" + iso2}></span> {activeLanguage}
</a>
);
}
const LanguageOption = (label, classLabel) => {
return (
<li
onClick={changeTounge}
data-id={label}
data-value={classLabel}
>
<Link to="#nav-locations">
<span className={"flag-icon flag-icon-" + classLabel}></span>
{" "}
{label}
</Link>
</li>
);
}
return (
<div className="primary-nav">
<ul className="navigation">
<li className="active">
<Link to="/">Home</Link>
</li>
<li className="has-child">
Opportunities
<div className="wrapper">
<div id="nav-homepages" className="nav-wrapper">
<ul>
{OpsOption("RealEstate", "Real Estate")}
{OpsOption("Vehicles", "Vehicles")}
{OpsOption("JobSearch", "Job Search")}
{OpsOption("PersonalCompany", "Personal Company")}
{OpsOption("Inves`enter code here`tInIdea", "Invest In Idea")}
</ul>
</div>
</div>
</li>
<li>
<Link to="/contact">Help & Support</Link>
</li>
<li className="has-child language">
{ActiveLanguage(language.iso2, language.speak)}
<div className="wrapper">
<div id="nav-languages" className="nav-wrapper">
<ul>
{LanguageOption("English", "us")}
{LanguageOption("British", "gb")}
{LanguageOption("Latviešu", "lv")}
{LanguageOption("Estonia", "ee")}
{LanguageOption("Lithuania", "lt")}
{LanguageOption("Russian", "ru")}
{LanguageOption("Deutch", "de")}
{LanguageOption("French", "fr")}
</ul>
</div>
</div>
</li>
</ul>
</div>
);
}
export default PrimaryNav;

There are probably tidier ways to do some of this, but this seems to work:
import React, { useState } from "react";
import { Link } from "react-router-dom";
export function PrimaryNav() {
const [language, setLanguage] = useState({ iso2: "us", speak: "English" });
return (
<div className="primary-nav">
<ul className="navigation">
<li className="active">
<Link to="/">Home</Link>
</li>
<li className="has-child">
Opportunities
<div className="wrapper">
<div id="nav-homepages" className="nav-wrapper">
<ul>
{OpsOption("RealEstate", "Real Estate")}
{OpsOption("Vehicles", "Vehicles")}
{OpsOption("JobSearch", "Job Search")}
{OpsOption("PersonalCompany", "Personal Company")}
{OpsOption("Inves`enter code here`tInIdea", "Invest In Idea")}
</ul>
</div>
</div>
</li>
<li>
<Link to="/contact">Help & Support</Link>
</li>
<li className="has-child language">
{ActiveLanguage(language.iso2, language.speak)}
<div className="wrapper">
<div id="nav-languages" className="nav-wrapper">
<ul>
{LanguageOption("English", "us", setLanguage)}
{LanguageOption("British", "gb", setLanguage)}
{LanguageOption("Latviešu", "lv", setLanguage)}
{LanguageOption("Estonia", "ee", setLanguage)}
{LanguageOption("Lithuania", "lt", setLanguage)}
{LanguageOption("Russian", "ru", setLanguage)}
{LanguageOption("Deutch", "de", setLanguage)}
{LanguageOption("French", "fr", setLanguage)}
</ul>
</div>
</div>
</li>
</ul>
</div>
);
}
function LanguageOption(label, classLabel, setLanguage) {
return (
<li
onClick={(event) => changeTounge(event, setLanguage, label, classLabel)}
data-id={label}
data-value={classLabel}
>
<Link to="#nav-locations">
<span className={"flag-icon flag-icon-" + classLabel}></span>
{" "}
{label}
</Link>
</li>
);
}
function changeTounge(e, setLanguage, label, classLabel) {
console.log("Write something!!");
console.log(e.currentTarget.dataset.id);
console.log(e.currentTarget.dataset.value);
setLanguage({ iso2: classLabel, speak: label });
}
function OpsOption(pageLink, label) {
return (
<li>
<Link to={"/" + pageLink}>{label}</Link>
</li>
);
}
function ActiveLanguage(iso2, activeLanguage) {
return (
<a href="#nav-languages">
<span className={"flag-icon flag-icon-" + iso2}></span> {activeLanguage}
</a>
);
}
export default PrimaryNav;

Related

The Profile Picture is not visible on the Top Bar

This a blog page using the Fullstack MERN Application. And it should show the uploaded Profile pic of the user when the particular user is Logged in on the Top bar. But in my case it is not showing up. Same thing is happening for the About me Image. But the difference is that the Image in the About me component is visible when the user is logging out and then logging in again.
The code for the Top Bar component is :
import { useContext } from "react";
import { Link } from "react-router-dom";
import { Context } from "../../context/Context";
import "./topbar.css";
export default function TopBar() {
const { user, dispatch } = useContext(Context);
const PF = "http://localhost:5000/images"
// console.log(PF+user.profilePic)
const handleLogout = () => {
dispatch({ type: "LOGOUT" });
};
return (
<div className="top">
<div className="topLeft">
<i className="topIcon fab fa-facebook-square"></i>
<i className="topIcon fab fa-twitter-square"></i>
<i className="topIcon fab fa-pinterest-square"></i>
<i className="topIcon fab fa-instagram-square"></i>
</div>
<div className="topCenter">
<ul className="topList">
<li className="topListItem">
<Link className="link" to="/">
HOME
</Link>
</li>
<li className="topListItem">
<Link className="link" to="/">
ABOUT
</Link>
</li>
<li className="topListItem">
<Link className="link" to="/">
CONTACT
</Link>
</li>
<li className="topListItem">
<Link className="link" to="/write">
WRITE
</Link>
</li>
<li className="topListItem" onClick={handleLogout}>
{user && "LOGOUT"}
</li>
</ul>
</div>
<div className="topRight">
{user ? (
<Link to="/settings">
<img className="topImg" src={PF + user.profilePic} alt="" />
</Link>
) : (
<ul className="topList">
<li className="topListItem">
<Link className="link" to="/login">
LOGIN
</Link>
</li>
<li className="topListItem">
<Link className="link" to="/register">
REGISTER
</Link>
</li>
</ul>
)}
<i className="topSearchIcon fas fa-search"></i>
</div>
</div>
);
}
COde For the Sidebar:
import axios from "axios";
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import "./sidebar.css";
import { useContext } from "react";
import { Context } from "../../context/Context";
export default function Sidebar() {
const [cats, setCats] = useState([]);
const { user } = useContext(Context);
const PF = "http://localhost:5000/images/";
useEffect(() => {
const getCats = async () => {
const res = await axios.get("/categories");
setCats(res.data);
};
getCats();
}, []);
return (
<div className="sidebar">
<div className="sidebarItem">
<span className="sidebarTitle">ABOUT ME</span>
{user && <img
src={PF + user.profilePic}
alt=""
/>}
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptate qui
necessitatibus nostrum illum reprehenderit.
</p>
</div>
<div className="sidebarItem">
<span className="sidebarTitle">CATEGORIES</span>
<ul className="sidebarList">
{cats.map((c) => (
<Link to={`/?cat=${c.name}`} className="link">
<li className="sidebarListItem">{c.name}</li>
</Link>
))}
</ul>
</div>
<div className="sidebarItem">
<span className="sidebarTitle">FOLLOW US</span>
<div className="sidebarSocial">
<i className="sidebarIcon fab fa-facebook-square"></i>
<i className="sidebarIcon fab fa-twitter-square"></i>
<i className="sidebarIcon fab fa-pinterest-square"></i>
<i className="sidebarIcon fab fa-instagram-square"></i>
</div>
</div>
</div>
);
}
The Image of the Top Bar
Also when the user is uploading the image a random no. is added in front of the file in the Data base which
I have manually remove to load the image to the server. As it is not able to read it like:
The random numbers in frond of the name of the file
I tried some Stack over flow answer like:TypeError: Cannot read property 'image' of null
This helped me with the Side bar problem but not fully.

make dropdown menu visible using react

I have following code with navbar and dropdown in it. All I want is to make the dropdown visible but I am not able to do it. What should I do. I have my code as
Header.jsx
import React, { useState } from 'react'
import { Link } from 'react-router-dom';
const Header = () => {
const [isVisible, setIsVisible] = useState(false);
return(
<div className="menu-container">
<nav className="nav">
<ul className="nav__menu">
<li className="nav__menu-item">
<Link to="Aboutus">About us</Link>
</li>
<li className="nav__menu-item">
<Link to="Myaccount">My account</Link>
</li>
<li className="nav__menu-item">
<Link to="Featured Product">Featured Product</Link>
</li>
<li className="nav__menu-item">
<Link to="WishList">WishList</Link>
</li>
<li className="nav__menu-items">
<Link to="Order Tracking">Order Tracking</Link>
</li>
<li className="nav__menu-items">
<Link to="English">English</Link>
{isVisible && (
<div>
<Link to className="box">English</Link>
<Link to className="box">German</Link>
<Link to className = "box">Spanish</Link>
</div>
)}
</li>
<li className="nav__menu-items">
<Link to="USD">USD</Link>
{isVisible && (
<div>
<Link to className="box">USD</Link>
<Link to className="box">INR</Link>
<Link to className="box">GBP</Link>
</div>
)}
</li>
</ul>
</nav>
</div>
)
}
export default Header
The code in the English and USD contains the dropdown but I am not able to make it possible visible. How can I make it visible.
Try this.
import React, { useState } from 'react'
import { Link } from 'react-router-dom';
const Header = () => {
const [isVisible, setIsVisible] = useState(false);
const toggle = () => {setIsVisible(!isVisible)}
return(
<div className="menu-container">
<nav className="nav">
<ul className="nav__menu">
<li className="nav__menu-item">
<Link to="Aboutus">About us</Link>
</li>
<li className="nav__menu-item">
<Link to="Myaccount">My account</Link>
</li>
<li className="nav__menu-item">
<Link to="Featured Product">Featured Product</Link>
</li>
<li className="nav__menu-item">
<Link to="WishList">WishList</Link>
</li>
<li className="nav__menu-items">
<Link to="Order Tracking">Order Tracking</Link>
</li>
<li className="nav__menu-items">
<Link to="English" onClick={toggle}>English</Link>
{isVisible && (
<div>
<Link to className="box">English</Link>
<Link to className="box">German</Link>
<Link to className = "box">Spanish</Link>
</div>
)}
</li>
<li className="nav__menu-items">
<Link to="USD" onClick={toggle}>USD</Link>
{isVisible && (
<div>
<Link to className="box">USD</Link>
<Link to className="box">INR</Link>
<Link to className="box">GBP</Link>
</div>
)}
</li>
</ul>
</nav>
</div>
)
}
export default Header
You don't change the value of isVisible in your code.
You should use setIsVisible function to set the new value of isVisible to true or false, as our want.

How do I create a portal for this navbar (React)

This is my index.html (Where the portal is supposed to lead to)
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="navbarRoot"></div>
<div id="root"></div>
</body>
Here is my navbar component
const Navbar = () => {
const [isOpen , setIsOpen] = useState(false)
const navButtonHandler = () => {
setIsOpen(!isOpen)
}
return (
<>
<nav className='navbar'>
<span><img src={logo} alt='home' className='logo' /></span>
<div className={`menuMask ${isOpen && "open"}`} onClick={navButtonHandler}></div>
<div className={`menuContainer ${isOpen && "open"}`}>
<ul className={`navitems ${isOpen && "open"}`}>
<a href="/" className='home'>
<li>Home</li>
</a>
<a href="/" className='whoWeHelp'>
<li>Who We Help</li>
</a>
<a href="/" className='services'>
<li>Services</li>
</a>
<a href="/" className='about'>
<li>About</li>
</a>
<a href="/" className='caseStudies'>
<li>Case Studies</li>
</a>
<li>
<PrimaryButton link={'https://hadizouhbi.website'}>Client Login</PrimaryButton>
</li>
<li>
<SecondaryButton link={'https://hadizouhbi.website'}>Contact</SecondaryButton>
</li>
</ul>
</div>
<div className={`navToggle ${isOpen && "open"}`} onClick={navButtonHandler}>
<div className='bar'>
</div>
</div>
</nav>
</>
)
}
Where in the code do I use this
{ReactDom.createPortal(<Navbar />, document.getElementById('navbarRoot'))}
Am i doing something wrong? because I have no idea where to put that line however I do think the syntax for that is correct just where to put it is the issue. Any help is greatly appreciated ! I am a beginner to react
If you meant to render the whole NavBar component as a portal then return in the Navbar should be like below.
import { useState } from "react";
import ReactDOM from "react-dom";
const domNode = document.getElementById("navbarRoot");
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const navButtonHandler = () => {
setIsOpen(!isOpen);
};
const navContent = (
<>
<nav className="navbar">
<span>{/* <img src={logo} alt="home" className="logo" /> */}</span>
<div
className={`menuMask ${isOpen && "open"}`}
onClick={navButtonHandler}
></div>
<div className={`menuContainer ${isOpen && "open"}`}>
<ul className={`navitems ${isOpen && "open"}`}>
<a href="/" className="home">
<li>Home</li>
</a>
...
...
</ul>
</div>
<div
className={`navToggle ${isOpen && "open"}`}
onClick={navButtonHandler}
>
<div className="bar"></div>
</div>
</nav>
</>
);
return ReactDOM.createPortal(navContent, domNode);
};
Use Navbar in any other place. In spite of where you try to render it in your component tree, it will always appear in the div with navbarRoot as the id.
export default function App() {
return (
<div className="App">
<Navbar />
</div>
);
}
the code {ReactDom.createPortal(<Navbar />, document.getElementById('navbarRoot'))} goes inside the return statement.
eg:
import Navbar from "component"
function MainPage(){
...
...
return(
<>
...
{ReactDom.createPortal(<Navbar />, document.getElementById('navbarRoot'))}
</>
);
}

How to anchor a component with prop?

I have a website that I used fixed menu options to anchor to the place I wanted ,below is a simple structure to demonstrate
mypage.jsx
<div className="mywork">
<TopbarWork menuOpen={menuOpen} setMenuOpen={setMenuOpen}/>
<MenuWork menuOpen={menuOpen} setMenuOpen={setMenuOpen}/>
<div className="sections">
<Product /> //origin
<Story workData={workData}/> //what I want to achieve
<Userflow workData = {workData}/>
<System workData={workData}/>
<FinalDesign workData={workData}/>
</div>
</div>
menu.jsx(click to go to the different anchors)
import './menu.scss'
export default function Menu({menuOpen,setMenuOpen}) {
return (
<div className={"menu " + (menuOpen && "active")}>
<ul>
<li onClick={()=>setMenuOpen(false)}>
Back
</li>
<li onClick={()=>setMenuOpen(false)}>
product
</li>
</ul>
</div>
)
}
Product.jsx(one of the components)
import { CheckCircle } from '#material-ui/icons';
import './product.scss'
export default function Product({workData}) {
return (
<div className="product" id="product"> //important
<div className="productLeft">
<div className="productIntro">
<p className="title">
{workData.title}
</p>
<p className="desc">
{workData.desc}
</p>
{workData.featured.map((feature)=>{
return(
<div className="featured">
<CheckCircle className="featuredIcon"/>
{feature.title}
</div>
)
})}
</div>
</div>
<div className="productRight">
<div className="item">
<img src="assets/desktop.jpeg" alt="" className="desktopImg" />
<img src={workData.productImg} alt="" className="productImg" />
</div>
</div>
</div>
)
}
So right now the problem is I have to pass "workData" into components , but after that if I click on the anchor, it would show Cannot read properties of undefined (reading 'workData') , I assume that I have to pass the workData too when I click on the anchor ?
But what's the right way to do that ?
EDIT
I tried using Link and history (react-router-dom) but failed , here's my code
menu.jsx
export default function MenuWork({menuOpen,setMenuOpen,workData}) {
console.log(workData)
const history = useHistory();
const handleClick = ()=>{
setMenuOpen(false)
history.push({
pathname:'/mywork#userflow',
state: { workData:workData}
})
}
return (
<div className={"menu " + (menuOpen && "active")}>
<ul>
<li onClick={()=>setMenuOpen(false)}>
Back
</li>
<li onClick={()=>setMenuOpen(false)}>
<Link to="#product">Product</Link>
</li>
<li onClick={()=>setMenuOpen(false)}>
<Link to={{
pathname:"/mywork#story",
state:{ workData:workData}
}}>Story</Link>
</li>
<li onClick={()=>handleClick()}>
userflow
</li>
</ul>
</div>
)
}
If I use Link and pass the state, it will return blank page without loading anything, and If I don't pass any state with Link , it will shows the same error as above.

Trying to toggle between icon to text on my navigation using React

I have some code down and it works but my problem is that it changes all of the icons at the same time when i scroll over just one. I only want the icon that I hover over to change, so any help would be appreciated.
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {isHovered: false};
this.toggleHover = this.toggleHover.bind(this);
}
toggleHover() {
this.setState(prevState => ({isHovered: !prevState.isHovered}));
}
render() {
return (
<section className="info-section">
<div className="logo">
MATT
</div>
<div className="info-box">
<ul className="nav-links">
<li onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>
{this.state.isHovered
? <a className="home active" href="/">Home</a>
: <a className="home active" href="/"><FontAwesomeIcon icon={faHome} /></a>
}
</li>
<li onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>
{this.state.isHovered
? About
: <FontAwesomeIcon icon={faUser} />
}
</li>
Maybe you can try to use CSS.
<ul className="nav-links">
<li>
<a href="/">
<span>Home</span>
<FontAwesomeIcon icon={faHome} />
</a>
</li>
<li>
<a href="/about">
<span>Home</span>
<FontAwesomeIcon icon={faUser} />
</a>
</li>
...
a {
span {
display: none;
}
&:hover {
span {
display: block;
}
/* hide the icon base on their html tag or class */
i {
display: none;
}
}
}
If you really want to handle this through Javascript (which I'm not suggesting), you can try this.
class App extends Component {
state = {
hover: ""
};
handleMouseEnter = key => {
this.setState({ hover: key });
};
handleMouseLeave = () => {
this.setState({ hover: "" });
};
render() {
const { hover } = this.state;
return (
<ul>
<li
onMouseEnter={() => this.handleMouseEnter("home")}
onMouseLeave={this.handleMouseLeave}
>
<a href="/">
{hover === "home" ? <span>Hover Home</span> : <span>Home</span>}
</a>
</li>
<li
onMouseEnter={() => this.handleMouseEnter("about")}
onMouseLeave={this.handleMouseLeave}
>
<a href="/about">
{hover === "about" ? <span>Hover about</span> : <span>about</span>}
</a>
</li>
</ul>
);
}
}

Resources