Can't find the missing key for the child - reactjs

novice developer here.
I can't seem to solve this missing key error. I've used the key prop for each time i've mapped but I can't seem to find the child with the missing key. please help!
I've tried putting key props in some of the child divs but still no success.
<h2 className="head-text">Skills & Experience</h2>
<div className="app__skills-container">
<motion.div className="app__skills-list">
{skills.map((skill) => (
<motion.div
whileInView={{ opacity: [0, 1] }}
transition={{ duration: 0.5 }}
className="app__skills-item app__flex"
key={skill.name}
>
<div
className="app__flex"
style={{ backgroundColor: skill.bgColor }}
>
<img src={urlFor(skill.icon)} alt={skill.name}/>
</div>
<p className="p-text">{skill.name}</p>
</motion.div>
))}
</motion.div>
<motion.div className="app__skills-exp">
{experience.map((experience) => (
<motion.div className="app__skills-exp-item" key={experience.year}>
<div className="app__skills-exp-year">
<p className="bold-text">{experience.year}</p>
</div>
<motion.div className="app__skills-exp-works">
{experience.works.map((work) => (
<>
<motion.div
whileInView={{ opacity: [0, 1] }}
transition={{ duration: 0.5 }}
className="app__skills-exp-work"
data-tip
data-for={work.name}
key={work.name}
>
<h4 className="bold-text">{work.name}</h4>
<p className="p-text">{work.company}</p>
</motion.div>
<ReactTooltip
id={work.name}
effect="solid"
arrowColor="#fff"
className="skills-tooltip"
>
{work.desc}
</ReactTooltip>
</>
))}
</motion.div>
</motion.div>
))}
</motion.div>
</div>
</>
);
};
export default AppWrap(
MotionWrap(Skills, 'app__skills'),
'skills', "app__whitebg"
);

Error is with <>...</> items in your
{experience.works.map((work) => (
<>
<motion.div key={work.name}>
{/* ... */}
</motion.div>
</>
))}
They are top-level DOM nodes inside of your map function, so they should have the key, not the child motion.div.
But they cant have key, so you will need to use Fragments. They are just the same.
import {Fragment} from "react";
{experience.works.map((work) => (
<Fragment key={work.name}>
<motion.div
whileInView={{ opacity: [0, 1] }}
transition={{ duration: 0.5 }}
className="app__skills-exp-work"
data-tip
data-for={work.name}
>
<h4 className="bold-text">{work.name}</h4>
<p className="p-text">{work.company}</p>
</motion.div>
<ReactTooltip
id={work.name}
effect="solid"
arrowColor="#fff"
className="skills-tooltip"
>
{work.desc}
</ReactTooltip>
</Fragment>
))}

According to react docs, the key has to be
a string that uniquely identifies a list item among its siblings
It is possible that the key you have provided for each element is not unique. For eg key={skill.name} key={experience.year} will not work if there are two list items with the same name or year respectively.
What you can do is use any uniquely identifiable property of the list item or the index of the array.
{skills.map((skill, index) => (
<motion.div
whileInView={{ opacity: [0, 1] }}
transition={{ duration: 0.5 }}
className="app__skills-item app__flex"
key={index}
>
<div
className="app__flex"
style={{ backgroundColor: skill.bgColor }}
>
<img src={urlFor(skill.icon)} alt={skill.name}/>
</div>
<p className="p-text">{skill.name}</p>
</motion.div>
))}

Related

Framer Motion Reorder misplacing my items

For some reason, in the first "reordering" framer-motion miscalculates my items' position. It definitely has something to do with the fact that I'm using this within a side panel because it is positioning them to a distance in the x-axis precisely the same as the width of my panel. Another problem I'm having is that the AnimatePrescese applies the height animation to the element itself, but not to the children... Any suggestions?
<Reorder.Group
axis="y"
className="flex flex-col p-0 m-0 list-none relative"
values={orderedItems}
onReorder={setOrderedItems}
ref={listRef}
>
<AnimatePresence>
{orderedItems?.map(item => {
const {
id,
referencePayload: { abbreviation, description, title, url }
} = item
return (
<Reorder.Item
key={id}
value={item}
dragConstraints={listRef}
dragElastic={0.1}
dragMomentum={false}
onDragStart={() => onDragStart(id)}
onDragEnd={() => onDragEnd(id)}
initial={{ height: 0 }}
animate={{ height: 'auto' }}
exit={{ height: 0 }}
>
<ProductItem
id={id}
url={url}
abbreviation={abbreviation}
title={title}
description={description}
onRemoveItem={handleRemoveFavourite}
hasUpdateError={isRemovalError}
isDragging={activeItemId === id}
/>
</Reorder.Item>
)
})}
</AnimatePresence>
</Reorder.Group>
Video with example => https://www.loom.com/share/cb2bf5f334f446459eeb1fc16772a3e4

multiple Swiper Thumb carousel navigation does not work

I am very new in React. I have multiple Swiper Thumb caroucels in one page.
also I have two filtered elements in my code which I want to show on display.my first carousel works perfectly in at first filtered item, but second one's navigation does not work, when I click, nothing happens.
const [thumbsSwiper, setThumbsSwiper] = useState(null);
const [thumbsSwiper1, setThumbsSwiper1] =useState(null)
this one works perfectly
<Swiper
style={{
"--swiper-navigation-color": "#fff",
"--swiper-pagination-color": "#fff",
}}
spaceBetween={10}
navigation={false}
thumbs={{ swiper: thumbsSwiper }}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper2"
>
{movie.images.map((item,index)=>{
return (
<SwiperSlide key={index} >
<img src={`http://.../${item}`} />
</SwiperSlide>
)
})}
</Swiper>
<Swiper
onSwiper={setThumbsSwiper}
spaceBetween={10}
slidesPerView={movie.images.length}
freeMode={true}
simulateTouch = {true}
watchSlidesProgress={true}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper"
>
{movie.images.map((item,index)=>{
return (
<SwiperSlide key={index} >
<img src={`http://.../${item}`} />
</SwiperSlide>
)
})}
</Swiper>
this one does not work, it is multiple array inside it and maybe this is a reason
<Swiper
style={{
"--swiper-navigation-color": "#fff",
"--swiper-pagination-color": "#fff",
}}
spaceBetween={10}
navigation={false}
thumbs={{ swiper: thumbsSwiper1 }}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper2"
>
{item.images.map((item,index)=>{
return (
<SwiperSlide key={index} >
<img src={`http://apicity.cgroup.ge/${item}`} />
</SwiperSlide>
)
})}
</Swiper>
<Swiper
onSwiper={setThumbsSwiper1}
spaceBetween={10}
slidesPerView={item.images.length}
freeMode={true}
watchSlidesProgress={true}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper"
>
{item.images.map((item,index)=>{
return (
<SwiperSlide key={index}>
<img src={`http://apicity.cgroup.ge/${item}`}/>
</SwiperSlide>
)
})}
</Swiper>
I thought I should change classes but it still does not worked, then I tried to change some property but still same result. help please

How can i fix the warning of " Each child in a list should have a unique "key" prop."?

Apparently this warning point to this (specifically in the key of skill):
{skills.map((skill) => (
<motion.div
whileInView={{ opacity: [0, 1] }}
transition={{ duration: 0.5 }}
className="app__skills-item app__flex"
key={skill.name}
>
<div
className="app__flex"
style={{ backgroundColor: skill.bgColor }}
>
<img />
<p>{skill.name}</p>
))}
{experiences.map((experience) => (
<motion.div
className="app__skills-exp-item"
key={experience.year}
>
<p>{experience.year}</p>
{experience.works.map((work) => (
<>
<motion.div
whileInView={{ opacity: [0, 1] }}
transition={{ duration: 0.5 }}
className="app__skills-exp-work"
data-tip
data-for={work.name}
key={work.name}
>
<h4>{work.name}</h4>
<p>{work.company}</p>
<ReactTooltip
id={work.name}
effect="solid"
arrowColor="#fff"
className="skills-tooltip"
>
{work.desc}
</>
))}
))}
I tried writing skills.name instead of skill.name and writing skill.id instead of skill.name also tried the same with work.name but i think that the issue is in skill and not in work.
You need to put the key in the fragment for the second map. Which means you will need to import { Fragment } from "react" and use it (I am talking on the experience.works.map line)
The general rule of thumb is if you are mapping [components] in React, you need a key.
You sadly cannot use the shorthand for Fragments <></> with keys currently however, hence the need to import it.
import { Fragment } from "react"
...
{experience.works.map((work,index) => (
<Fragment key={index}>
<motion.div
whileInView={{ opacity: [0, 1] }}
transition={{ duration: 0.5 }}
className="app__skills-exp-work"
data-tip
data-for={work.name}
key={work.name}
>
<h4>{work.name}</h4>
<p>{work.company}</p>
<ReactTooltip
id={work.name}
effect="solid"
arrowColor="#fff"
className="skills-tooltip"
>
{work.desc}
</>
))}

How to use ternary operator inside map

I am trying to use a ternary operator inside a map, but not to sure why this is wrong? Getting a parsing error at the end of the ternary
code:
return(
<div className='Card'>
<div className='TableTopbar ScheduleGrid'>
<div>id</div>
<div>interval</div>
<div>project_id</div>
<div>database</div>
<div>create_timestamp</div>
<div>create_user_id</div>
<div>Edit</div>
</div>
{scheduleData.map((schedule)=>
{UsageMode === 'Read' ?
<div className='Table ScheduleGrid'>
<div>{schedule.id}</div>
<div>{schedule.interval}</div>
<div>{schedule.project_id}</div>
<div>{schedule.database}</div>
<div>{schedule.create_timestamp}</div>
<div>{schedule.create_user_id}</div>
<div>
<EditIcon
style={{padding: '2px', width: '0.8em', height: '0.8em', marginRight: '5px'}}
className='CircleButton'
onClick={onEditScheduleClick}
/>
</div>
</div>
:
<div>ID</div>
}
)
)
export default scheduleRowTwo
Updated code:
return(
<div className='Card'>
<div className='TableTopbar ScheduleGrid'>
<div>id</div>
<div>interval</div>
<div>project_id</div>
<div>database</div>
<div>create_timestamp</div>
<div>create_user_id</div>
<div>Edit</div>
</div>
{scheduleData.map((schedule)=>
(
{UsageMode === 'Read' ?
<div className='Table ScheduleGrid'>
<div>{schedule.id}</div>
<div>{schedule.interval}</div>
<div>{schedule.project_id}</div>
<div>{schedule.database}</div>
<div>{schedule.create_timestamp}</div>
<div>{schedule.create_user_id}</div>
<div>
<EditIcon
style={{padding: '2px', width: '0.8em', height: '0.8em', marginRight: '5px'}}
className='CircleButton'
onClick={onEditScheduleClick}
/>
</div>
</div>
:
<div>ID</div>
}
)
)
export default scheduleRowTwo
Updated error:
Apparently, your outermost div does not have a closing tag, thus resulting in an error.
Also, you're missing a return statement.
return (
<div className="Card">
<div className="TableTopbar ScheduleGrid">
<div>id</div>
<div>interval</div>
<div>project_id</div>
<div>database</div>
<div>create_timestamp</div>
<div>create_user_id</div>
<div>Edit</div>
</div>
{scheduleData.map((schedule) => {
return UsageMode === "Read" ? (
<div className="Table ScheduleGrid">
<div>{schedule.id}</div>
<div>{schedule.interval}</div>
<div>{schedule.project_id}</div>
<div>{schedule.database}</div>
<div>{schedule.create_timestamp}</div>
<div>{schedule.create_user_id}</div>
<div>
<EditIcon
style={{
padding: "2px",
width: "0.8em",
height: "0.8em",
marginRight: "5px",
}}
className="CircleButton"
onClick={onEditScheduleClick}
/>
</div>
</div>
) : (
<div>ID</div>
);
})}
</div>
);
Try this code. Should work.
You should enclose this code block with parentheses because you're trying to implicitly return an object (without the return keyword):
{UsageMode === 'Read' ?
<div className='Table ScheduleGrid'>
<div>{schedule.id}</div>
<div>{schedule.interval}</div>
<div>{schedule.project_id}</div>
<div>{schedule.database}</div>
<div>{schedule.create_timestamp}</div>
<div>{schedule.create_user_id}</div>
<div>
<EditIcon
style={{padding: '2px', width: '0.8em', height: '0.8em', marginRight: '5px'}}
className='CircleButton'
onClick={onEditScheduleClick}
/>
</div>
</div>
:
<div>ID</div>
}

How to make react-spring <Spring> replay animation?

I have a simple react site which displays drinks from the drinks-api. It basically works like this: when user presses button, the query gets updated, fetchItems runs and items are displayed this way
<Spring from={{ opacity: 0, marginTop: 100 }} to={{ opacity: 1, marginTop: 0 }} config={{ delay: 400 }}>
{(props) => (
<div style={props}>
{drinks
? drinks.map((drink) => (
<DrinkCard
title={drink.strDrink}
image={drink.strDrinkThumb}
alcohol={drink.strAlcoholic}
category={drink.strCategory}
/>
))
: () => (
<div className="col-6 col-md-4 p-0">
<h1>NO RESULTS</h1>
</div>
)}
</div>
)}
</Spring>
For now this animation works only once when page loads. How do I force it to run on every search?
You should add reset to your Spring component like this:
<Spring
from={{ opacity: 0, marginTop: 100 }}
to={{ opacity: 1, marginTop: 0 }}
config={{ delay: 400 }}
reset
>
Here is an example: https://codesandbox.io/s/dank-moon-sq7v9?file=/src/App.js:348-503

Resources