React duplicating list items when adding multiple components? - reactjs

The below link is to a codesandbox for a project I am working on. The SideNav list items match the slides for navigation. The problem is that when I add an another different component (like other for example)to the return statement of slideshow.js, the list items are thrown off/incorrect/duplicated. I can't figure out why and am at the point of thinking its a react thing, or maybe a dependency I am using? console logging doesnt help me much so far.
ps: the list items are indexed by the "slide-title" class in AppContext.js.
https://codesandbox.io/s/test-r4ov3?file=/src/App.js
This Works Fine
<Fragment>
<Slide ref={slideRef} {...slideProperties} className="slide-container">
{SlideData.map((item, index) => (
<p key={index} className="slide-title">
{item.title}
</p>
))}
</Slide>
</Fragment>
This does not
<Fragment>
<Slide ref={slideRef} {...slideProperties} className="slide-container">
{SlideData.map((item, index) => (
<p key={index} className="slide-title">
{item.title}
</p>
))}
<div className="slide-title">Other</div><---ADDED
</Slide>
</Fragment>
BEFORE ADDING -LIST ITEMS MATCH
AFTER ADDING A COMPONENT- LIST ITEMS DUPLICATE?

This was a bug addressed in react-slideshow-image with version 3.4.7 as reported on the GitHub repo. There is also a workaround where you can use {[...mappeditems, SomeOtherComponent/>]} but it shouldn't be necessary now.

Related

What is best practice for filtering a map in React JSX return

When returning the below in a component to render cards where would you put a filter on something like this?
{state.messages.map((message, index) => (
<div key={index}>
<Center>
<Box
maxW={'850px'}
w={'full'}
boxShadow={'2xl'}
rounded={'md'}
p={6}
overflow={'hidden'}
>
<Flex>
<h4>UserID: {message.id}</h4>
<Spacer/>
<Button onClick={'test'} colorScheme='teal' variant='solid' >
<DeleteIcon/>
</Button>
</Flex>
<h3>User(email for now): {message.user} </h3>
<h2 >message: {message.message}</h2>
<p>Date: {message.createdAt}</p>
</Box>
</Center>
<Container height={50}/>
</div>
))}
My first thought was something like
{state.messages.filter((message) => message.id).map((message, index) => (...
this doesn't return anything but a regular map so not it probably just an example
...}
So hoping someone can explain what best practice is for filtering a map in returned jsx. can you even do what I'm trying to do without callstack errors?
edit: someone said the snippet is the right way, so i'll fix it in the morning and update/close this. if anyone else wants to confirm overnight too many thanks
Your approach is the best approach.
Firstly, filter and map is the clearest functions to use.
Secondly, it's better to use filter before map for two reasons:
By removing unwanted items before mapping them, you save computations as you don't map the unwanted items.
The map function returns JSX.Elements which is much harder to apply a filter on than the objects in state.messages.
As the other user in the thread suggested this is solution I went with and it works great
{state.messages.filter((message) => message.id === user?.issuer).map((message, index) => (
<div key={index}>
<Center>
<Box
maxW={'850px'}
w={'full'}
boxShadow={'2xl'}
rounded={'md'}
p={6}
overflow={'hidden'}
>
<Flex>
<h4>UserID: {message.id}</h4>
<Spacer/>
<Button onClick={'test'} colorScheme='teal' variant='solid' >
<DeleteIcon/>
</Button>
</Flex>
<h3>User(email for now): {message.user} </h3>
<h2 >message: {message.message}</h2>
<p>Date: {message.createdAt}</p>
</Box>
</Center>
<Container height={50}/>
</div>
))}
user?.issuer is context auth ID so it maps based on having the ID of a previous post === to your auth id

Warning: Each child in a list should have a unique "key" prop- Custom Pagination Component [duplicate]

I'm building an app using the Google Books API and I appear to be passing a unique key to each child in the list, but the error won't go away. I must be doing something wrong but I'm not sure what.
const BookList = (props) => {
//map over all of the book items to create a new card for each one in the list
const books = props.books.data.items.map((book) => {
console.log(book.id);
return (
<div className="col col-lg-4 grid-wrapper">
<BookCard
key={book.id}
image={book.volumeInfo.imageLinks.thumbnail}
title={book.volumeInfo.title}
author={book.volumeInfo.authors[0]}
description={book.volumeInfo.description}
previewLink={book.volumeInfo.previewLink}
buyLink={book.saleInfo.buyLink}
/>
</div>
);
});
return <div>{books}</div>;
};
Notice that after the return in const books I have a console.log(book.id), which will display all 10 unique id keys in the console. But when I try to pass it to the child of this component using key={book.id}, I get this error.
The key needs to go on the outermost returned element. In your specific case, that means changing this:
<div className="col col-lg-4 grid-wrapper">
<BookCard
key={book.id}
to this:
<div className="col col-lg-4 grid-wrapper" key={book.id}>
<BookCard
I was using React fragments in my map() call in their simple syntax form, and was running into the same warnings with the code below:
<>
<h3>{employee.department}</h3>
<TableRow
key={employee.id}
cellValues={["Name", "Title"]} />
<TableRow
key={employee.id}
cellValues={[employee.name, employee.title]}
/>
</>
Building off the accepted answer, I realized I needed the outermost element to have the ID. I learned of an alternate syntax for React fragments that allows one to put an ID on it. The resulting code below caused the warnings to go away:
<React.Fragment key={employee.id}>
<h3>{employee.department}</h3>
<TableRow
cellValues={["Name", "Title"]} />
<TableRow
cellValues={[employee.name, employee.title]}
/>
</React.Fragment>

React-Reveal breaks in combination with React-Scroll

I am working on a portfolio site with React.js as a self-learning project for my software engineering course. My goal is to make a heavily animated portfolio site.
I am currently experiencing a bug where the entire page freezes up for a bit when using a react-reveal animation on my photo in the about section (About.js component). However, the animation works just fine on the text directly next to the image.
The navbar (Navbar.js component) contains the react-scroll code which is just simple Link to the id of each section. One thing to note is that the animations also work fine if the user manually scrolls. I have also tried in a variety of browsers.
I thought that the issue might have been caused by having too many animations running at once, causing lag, but I tested multiple react-reveal animations together and it has no problem so long as there is no scroll taking place. I also tried delaying the animations, but that led to the same frozen results. I included a video of the problem and the project github linked below.
About.js
...
const About = () => {
return (
<>
<div id='about' className='aboutSection'>
<br />
<div className='aboutBox'>
<div className='aboutText'>
<Fade left><h1>About Me</h1>
<p>Placeholder for purposes of post</p>
</Fade>
</div>
<div className='aboutPicture'>
<Fade right><img src={headshot} id='headshot' /></Fade> {/*This fade is causing the issues*/}
</div>
</div>
</div>
</>
)
}
Navbar.js
...
<div className='mainNav'>
<ul>
{/* <NavLink to='/' exact className='nav' style={{ textDecoration: 'none' }}> */}
<li id='title'><Link to='top' smooth={true} ignoreCancelEvents><button className='navTitleText'>Mitchell Conrad</button></Link></li>
{/* </NavLink> */}
<li className='nav-item'><Link to='about' spy={true} smooth={true} ignoreCancelEvents><Button scrollButton={props.scrollNav}> About </Button></Link></li>
<li className='nav-item'><Link to="projects" spy={true} smooth={true} ignoreCancelEvents><Button scrollButton={props.scrollNav}> Projects </Button></Link></li>
<li className='nav-item'><Link to="resume" spy={true} smooth={true} ignoreCancelEvents><Button scrollButton={props.scrollNav}> Resume </Button></Link></li>
<li id='contact' className='nav-item'><Button onClick={() => modalRef.current.open()}> Contact </Button></li>
</ul>
</div>
...
Video of Issue
Full Project Github Link
I appreciate any advice/direction to take to work around this or fixes. Maybe I am missing something simple here, but I can't figure it out for the life of me.

Can I use React.Fragment for list rendering while have the "key" assigned?

Can I use React.Fragment inside the list rendering and assign a key to this 'Fragment' parent?
I'm trying to build a projects list layout using css grid, which requires all the elements is direct child of the container. Let's say the desired result will be look something like this.
<div className="container">
<img src="imgPathFor1stProject">
<h1>title for 1st project</h1>
<p>description for 1st project</p>
<img src="imgPathFor2ndProject">
<h1>title for 2nd project</h1>
<p>description for 2nd project</p>
...
</div>
But we all know the list render requires to return a single enclosing tag which we can tackle by using React.Fragment. Then the jsx will look like this:
projects.map(project => (
<>
<img src={project.imagePath}/>
<h1>{project.title}</h2>
<p>{project.description}</p>
</>
));
But here comes the problem, I can't assign a key to each child of the list since there's no actual element that wrapping all these elements.
I tried do: < key={project.id}> and <React.Fragment key={project.id}>, both doesn't work.
Is there a way to solve this? I still want to apply display:grid on .container element.
Thanks!
https://reactjs.org/docs/fragments.html
Keyed Fragments
Fragments declared with the explicit syntax may have keys. A use case for this is mapping a collection to an array of fragments — for example, to create a description list:
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
// Without the `key`, React will fire a key warning
<React.Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</React.Fragment>
))}
</dl>
);
}

Warning: Each child in a list should have a unique "key" prop

I'm building an app using the Google Books API and I appear to be passing a unique key to each child in the list, but the error won't go away. I must be doing something wrong but I'm not sure what.
const BookList = (props) => {
//map over all of the book items to create a new card for each one in the list
const books = props.books.data.items.map((book) => {
console.log(book.id);
return (
<div className="col col-lg-4 grid-wrapper">
<BookCard
key={book.id}
image={book.volumeInfo.imageLinks.thumbnail}
title={book.volumeInfo.title}
author={book.volumeInfo.authors[0]}
description={book.volumeInfo.description}
previewLink={book.volumeInfo.previewLink}
buyLink={book.saleInfo.buyLink}
/>
</div>
);
});
return <div>{books}</div>;
};
Notice that after the return in const books I have a console.log(book.id), which will display all 10 unique id keys in the console. But when I try to pass it to the child of this component using key={book.id}, I get this error.
The key needs to go on the outermost returned element. In your specific case, that means changing this:
<div className="col col-lg-4 grid-wrapper">
<BookCard
key={book.id}
to this:
<div className="col col-lg-4 grid-wrapper" key={book.id}>
<BookCard
I was using React fragments in my map() call in their simple syntax form, and was running into the same warnings with the code below:
<>
<h3>{employee.department}</h3>
<TableRow
key={employee.id}
cellValues={["Name", "Title"]} />
<TableRow
key={employee.id}
cellValues={[employee.name, employee.title]}
/>
</>
Building off the accepted answer, I realized I needed the outermost element to have the ID. I learned of an alternate syntax for React fragments that allows one to put an ID on it. The resulting code below caused the warnings to go away:
<React.Fragment key={employee.id}>
<h3>{employee.department}</h3>
<TableRow
cellValues={["Name", "Title"]} />
<TableRow
cellValues={[employee.name, employee.title]}
/>
</React.Fragment>

Resources