I have 6 div elements that I want to be able to click one of and have the className change for just the div I've clicked on. Currently, when I click on one div, ALL the div classNames change. This idea came from a vanilla JS concept that I'm trying to convert into a React component. I'm not sure where/what is going wrong, if anyone can tell me how to prevent the sibling divs' onClicks from being fired or if what I have is wrong fundamentally, I would be eternally grateful. This is what I have so far:
import React, { useState} from "react";
import { Panels } from "../../components/index";
import { data } from "../../constants/index";
import "./gallery.css";
const Gallery = () => {
const [isOpen, setIsOpen] = useState(false);
const toggleOpen = () => {
setIsOpen(!isOpen);
};
return (
<div className="panels">
{data.restaurants.map((restaurant, index) => (
<div
className={`panel panel${index} ${isOpen ? "open open-active" : ""}`}
onClick={toggleOpen}
>
<Panels
key={restaurant.name index}
description={restaurant.description}
name={restaurant.name}
website={restaurant.website}
/>
</div>
))}
</div>
);
};
export default Gallery;
This is my Panels Component code:
import React from "react";
const Panels = ({ name, description, website }) => {
return (
<div className="panel_text">
<p>{description}</p>
<p>{name}</p>
<a href={website}>
<p>Visit {name}</p>
</a>
</div>
)};
export default Panels;
Aaaand this is my CSS code:
*, *:before, *:after {
box-sizing: inherit;
}
.panels {
min-height: 100vh;
overflow: hidden;
display: flex;
}
.panel, .panel_text {
background: '#fff';
box-shadow: inse 0 0 0 5px rgba(255, 255, 255, 0.1);
color: var(--color-golden);
text-align: center;
align-items: center;
transition:
font-size 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11),
flex 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11);
font-size: 20px;
background-size: cover;
background-position: center;
flex: 1;
justify-content: center;
display: flex;
flex-direction: column;
}
.panel0 {background-image: url(../../assets/defuegocarousel.jpg);}
.panel1 {background-image: url(../../assets/HaydenslakeSz.jpg);}
.panel2 {background-image: url(../../assets/stonecliffSz.jpg);}
.panel3 {background-image: url(../../assets/shigezooutside.png);}
.panel4 {background-image: url(../../assets/southparkSz.jpeg);}
.panel5 {background-image: url(../../assets/lechonoutside.jpg);}
.panel > * {
margin: 0;
width: 100%;
transition: transform 0.5s;
flex: 1 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.panel > *:first-child {transform: translateY(-100%);}
.panel.open-active > *:first-child {transform: translateY(0); }
.panel > *:last-child { transform: translateY(100%); }
.panel.open-active > *:last-child {transform: translateY(0); }
.panel_text p, a {
text-transform: uppercase;
}
.panel p:nth-child(2) {
font-size: 4rem;
}
.panel.open {
flex: 5;
font-size: 40px;
}
@media only screen and (max-width: 600px) {
.panel p {
font-size: 1rem;
}
}
CodePudding user response:
You're saving a boolean value as a div element is open or not. So this value is considered for all div element's because there is no identifier which div element is open. You need to save a div element value to identify the open div element.
So you can use a div element's index instead of a boolean value. For example, try the below code.
import React, { useState} from "react";
import { Panels } from "../../components/index";
import { data } from "../../constants/index";
import "./gallery.css";
const Gallery = () => {
const [isOpen, setIsOpen] = useState(null);
return (
<div className="panels">
{data.restaurants.map((restaurant, index) => (
<div
className={`panel panel${index} ${isOpen === index ? "open open-active" : ""}`}
onClick={() => setIsOpen(index)}
>
<Panels
key={restaurant.name index}
description={restaurant.description}
name={restaurant.name}
website={restaurant.website}
/>
</div>
))}
</div>
);
};
export default Gallery;
CodePudding user response:
your isOpen state is common between all your div's you should specify a unique value for isOpen of each div
you can change your isOpen state to an object like this :
import React, { useState} from "react";
import { Panels } from "../../components/index";
import { data } from "../../constants/index";
import "./gallery.css";
const Gallery = () => {
const [isOpen, setIsOpen] = useState({});
const toggleOpen = (index) => {
setIsOpen(prevState => {...prevState ,[index]:!(!!prevState[index]) });
};
return (
<div className="panels">
{data.restaurants.map((restaurant, index) => (
<div
className={`panel panel${index} ${isOpen[index] ? "open open-active" : ""}`}
onClick={()=>toggleOpen(index)}
>
<Panels
key={restaurant.name index}
description={restaurant.description}
name={restaurant.name}
website={restaurant.website}
/>
</div>
))}
</div>
);
};
export default Gallery;
