My unique key is not working for my array mapping.
The Link component is from react-scroll. I've therefore wrapped it into a tag, and setting the key here (thinking this could be where the issue is from)
I understand using index for setting a unique key is bad practice. But I am really just trying to remove the warning message a this point!
Any help would be very much appreciated.
My code:
import styles from '../styles/NavImage.module.css'
import { Link } from 'react-scroll'
const NAVLINKSHOVER = ['About', 'Club', 'Team', 'Timing', 'FAQ']
const NavImage = ({toggleFaq, toggleState, hoveredIndex, setHoveredIndex}) => {
const handleClick = () => {
toggleFaq();
};
return (
<nav className={styles.navbar}>
<div className={styles.linkContainer}>
{
NAVLINKSHOVER.map ((navLink, index) => {
if (navLink === 'FAQ') {
return (
toggleState?(
<div key={index}>
<Link
to="main"
smooth={true}
offset={0}
duration={0}
onClick={handleClick}
className={`${styles.navLinks} ${styles.linkNotActive}`}
>FAQ
</Link>
</div>
):(
<div key={index.toString()}>
<Link
to="faq"
smooth={true}
offset={500}
duration={200}
onClick={handleClick}
className={`${styles.navLinks} ${styles.linkNotActive}`}
>FAQ
</Link>
</div>
)
)
}
return (
<>
<a
className={`${styles.navLinks} ${hoveredIndex === index? styles.linkActive : styles.linkNotActive}`}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(-1)}
key={index.toString()}
>
{navLink}
</a>
{
index!==NAVLINKSHOVER.length-1? <p className={styles.divider}> | </p> : null
}
</>
)
})
}
</div>
</nav>
);
}
export default NavImage;
You're returning a key in the case of FAQ, but not in any other cases; see here?
return (
<> <---- no key
<a
The top component returned needs a key. The string being iterated over would serve nicely without using the index.
{
NAVLINKSHOVER.map ((navLink, index) => {
if (navLink === 'FAQ') {
return (
toggleState?(
<div key="faq-main">
<Link
to="main"
smooth={true}
offset={0}
duration={0}
onClick={handleClick}
className={`${styles.navLinks} ${styles.linkNotActive}`}
>FAQ
</Link>
</div>
):(
<div key="faq">
<Link
to="faq"
smooth={true}
offset={500}
duration={200}
onClick={handleClick}
className={`${styles.navLinks} ${styles.linkNotActive}`}
>FAQ
</Link>
</div>
)
)
}
return (
<React.Fragment key={navLink}>
<a
className={`${styles.navLinks} ${hoveredIndex === index? styles.linkActive : styles.linkNotActive}`}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(-1)}
key={index.toString()}
>
{navLink}
</a>
{
index!==NAVLINKSHOVER.length-1? <p className={styles.divider}> | </p> : null
}
</React.Fragment>
)
})
}
You should wrap the bottom return statement in a div and then give that div a key, if you want to get rid of the warning.
<div key={index.toString()}>
<a
className={`${styles.navLinks} ${
hoveredIndex === index ? styles.linkActive : styles.linkNotActive
}`}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(-1)}
>
{navLink}
</a>
{index !== NAVLINKSHOVER.length - 1 ? (
<p className={styles.divider}> | </p>
) : null}
</div>
Pls note it is still a bad practice to use index as a key.
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.
I was unable to populate the with the correct array information. This is now working with the fix below.
Here is the corrected file.
renderComments(){
if (this.props.selectedDish != null) {
const commentList = this.props.selectedDish.comments;
return (
<div>
<h4>Comments</h4>
{commentList.map((comment) => {
return (
<ul className="list-unstyled" >
<li>
<p>{comment.comment}</p>
<p> -- {comment.author}{" "}
{Intl.DateTimeFormat("en-US",{
month: "short",
day: "2-digit",
year: "numeric"}).format(new Date(comment.date))}
</p>
</li>
</ul>
);
})};
</div>
);
} else {
return (
<div></div>
);
}
}
Thank you sava128
You should assign comments like you did with dish.name and dish.description
try:
renderComments() {
const dish = this.props.selectedDish;
if (dish) {
const commentList = dish.comments;
console.log("test2", commentList);
return (
<div>
<h4>Comments</h4>
<ul className="list-unstyled">
{commentList.map((comment) => {
return (
// list items here
)
})}
</ul>
</div>
);
} // else here
}
Relatively new to React and trying to sort the mapped prop nearbyRestaurants alphabetically by place.name. Is there a way I can chain the sort method to the end of the map method to alphabetize the list?
export default function RestaurantList({nearbyRestaurants}) {
return (
<div>
<ul>
<li className="list-header">Restaurants</li>
{nearbyRestaurants.map((place) => (
<div>
<li>
<div>{place.name}</div>
<div>{place.vicinity}</div>
</li>
</div>
))}
</ul>
</div>
);
}
Sort the array before mapping it.
function sortAlphabetically(a,b){
return a.name.localeCompare(b.name)
}
export default function RestaurantList({nearbyRestaurants}) {
return (
<div>
<ul>
<li className="list-header">Restaurants</li>
{nearbyRestaurants.sort(sortAlphabetically).map((place) => (
<div>
<li>
<div>{place.name}</div>
<div>{place.vicinity}</div>
</li>
</div>
))}
</ul>
</div>
);
}
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;