I'm mapping through data, I want to click on an image and have a modal popup with the data.title and data.info. Each modal is only showing the last data from my array. I've read that all the modals are popping up together and I'm only seeing the last one but I don't quite understand how to solve the problem, particularly with function components in React.Im tried to use the solution that i found in the stackoverflow for the same question as mine but i dont have sucess, i start to learn react and javascript 1 week ago.
import { Container, Grid, Card, Modal, Typography, Button } from '@mui/material';
import { Box, height } from '@mui/system';
import React from 'react';
import { DataWorks } from '../DataWorks';
import './WorksPage.css';
import 'animate.css';
import './ModalReact.css'
const style = {
position: 'absolute',
top: '50%',
left: '50%',
width: { xs: '80vw', sm: '80vw', md: '70vw', lg: '60vw', xl: '45vw' },
height: '90vh',
transform: 'translate(-50%, -50%)',
bgcolor: 'white',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
const WorksPage = () => {
const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const Content = DataWorks.map((item) => (
(
<>
<Grid item xs={12} sm={6} md={6} xl={6}>
<Box className="content-box" mt={5}>
<Card className='animate__animated animate__backInUp' sx={{ backgroundColor: "transparent", boxShadow: "0px 0px 0px 0px", padding: { xs: "0 20px", sm: "0", md: "0", xl: "0" } }}>
<a onClick={handleOpen} style={{ color: "black", textDecoration: "none" }}>
<div className="zoom" key={item.id}>
<img className='works-img' width="100%" src={item.imagemg}></img>
</div>
<h3 className='font-subtitle'>{item.empresa}</h3>
<h2 className='font-title'>{item.titulo}</h2>
</a>
</Card>
</Box>
</Grid>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<Typography id="modal-modal-title" >
{item.empresa}
</Typography>
<Typography id="modal-modal-description" >
{item.titulo}
</Typography>
<img className='img-modal' src={item.imagem} />
<Typography id="modal-modal-title" >
Insight
</Typography>
<Typography id="modal-modal-description" >
{item.insight}
</Typography>
<Typography id="modal-modal-title" >
Ideia
</Typography>
<Typography id="modal-modal-description" >
{item.ideia}
</Typography>
<Typography id="modal-modal-title" >
Impacto
</Typography>
<Typography id="modal-modal-description" >
{item.impacto}
</Typography>
</Box>
</Modal>
</>
)
))
return (
<Container maxWidth="xl" style={{ marginTop: "70px" }}>
<Grid container>
{Content}
</Grid>
</Container>
);
}
export default WorksPage;
And thats is my data
export const DataWorks=[
{
imagemg: "https://res.cloudinary.com/duyvaptsa/image/upload/v1648062300/hlqa-social/CafeDoCafeSanFrancisco_adj4un.png",
imagem: "https://res.cloudinary.com/duyvaptsa/image/upload/v1647972316/hlqa-social/cafe_pxbn94.png",
empresa: "Café San Francisco",
titulo: "The Premium Menu",
link: "/work",
insight:"O que pedir? Bebida especial, cafezinho tradicional, suco, chá gelado? Pão de queijo, prensadinho, lanche no waffle de pão de queijo, bolo?",
ideia:"Realização de um ensaio fotográfico e desenvolvimento de uma linha estratégica de produtos. Para conceito visual, utilização de filtros, tipografia, e enquadramento para maior impacto na plataforma.",
impacto:"Novo visual na plataforma, acarretando aumento de engajamento e base de seguidores. Tudo isso gerando novos clientes para o café e aumento de vendas de produtos chaves.",
},
{
imagemg: "https://res.cloudinary.com/duyvaptsa/image/upload/v1648062304/hlqa-social/CafeSanFrancisco_gvq34f.png",
imagem: "https://res.cloudinary.com/duyvaptsa/image/upload/v1647972319/hlqa-social/expresso_ktc9xx.png",
empresa: "Café San Francisco",
titulo: "Universe of coffe",
link: "/work",
insight:"Muitas pessoas frequentam cafés para ter um momento especial, onde possam se distrair, conversar e, claro, matar a fome e repor a energia.",
ideia:"Exploramos o clima e hábitos relacionados à estação do ano, curiosidades sobre ingredientes dos produtos e gostos particulares, frases inspiracionais e preferências dos clientes relacionadas ao cardápio para criar uma linha de conteúdos especiais para o café.",
impacto:"Aumento do engajamento e conversas, crescimento da base de seguidores e mudança no visual das plataformas do café.",
},
{
imagemg: "https://res.cloudinary.com/duyvaptsa/image/upload/v1648062302/hlqa-social/PetOmegaVeterinaria_xiiya0.png",
imagem: "https://res.cloudinary.com/duyvaptsa/image/upload/v1647972322/hlqa-social/dog_kodng8.png",
empresa: "Ômega Veterinária",
titulo: "Pet`s Life",
link: "/work",
insight:"Conviver com pets gera momentos únicos. Todo o carinho e atenção que temos com nossos amigos peludos fazem com que nosso dia a dia seja melhor, com companhia e brincadeiras.",
ideia:"Exploramos o universo comportamental e de rotina dos pets, curiosidades, dicas de saúde e datas comemorativas. Tudo isso somado a criação de uma linha institucional da clínica, referência em exames de imagem na região da Baixada Santista.",
impacto:"Forte crescimento da base de seguidores, excelente engajamento e conexão aos conteúdos criados e adesão de novos clientes para a clínica.",
},
]
Open a modal if the items of the specific object when i click in the image or in the card.
CodePudding user response:
So the issue is that all of the modals created rely on the same state open
from the WorksPage
component. A way to work around this is to create a completely new component to hold its own state
within. The jsx in Content should be a new component passing it the item
as props for the component. And map
through the data and use the component like below in your WorksPage
component.
const ContentItem = ({ item }) => {
const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
return (
<>
<Grid item xs={12} sm={6} md={6} xl={6}>
<Box className="content-box" mt={5}>
<Card className='animate__animated animate__backInUp' sx={{ backgroundColor: "transparent", boxShadow: "0px 0px 0px 0px", padding: { xs: "0 20px", sm: "0", md: "0", xl: "0" } }}>
<a onClick={handleOpen} style={{ color: "black", textDecoration: "none" }}>
<div className="zoom" key={item.id}>
<img className='works-img' width="100%" src={item.imagemg}></img>
</div>
<h3 className='font-subtitle'>{item.empresa}</h3>
<h2 className='font-title'>{item.titulo}</h2>
</a>
</Card>
</Box>
</Grid>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<Typography id="modal-modal-title" >
{item.empresa}
</Typography>
<Typography id="modal-modal-description" >
{item.titulo}
</Typography>
<img className='img-modal' src={item.imagem} />
<Typography id="modal-modal-title" >
Insight
</Typography>
<Typography id="modal-modal-description" >
{item.insight}
</Typography>
<Typography id="modal-modal-title" >
Ideia
</Typography>
<Typography id="modal-modal-description" >
{item.ideia}
</Typography>
<Typography id="modal-modal-title" >
Impacto
</Typography>
<Typography id="modal-modal-description" >
{item.impacto}
</Typography>
</Box>
</Modal>
</>
}
WorksPage
return (
<Container maxWidth="xl" style={{ marginTop: "70px" }}>
<Grid container>
{DataWorks.map((item) => (
// note below
<ContentItem item={item} key={item.??} />
)}
</Grid>
</Container>
);
CodePudding user response:
The issue is that you have a lot of <Model>
components, but only one state variable open
, so you are correct. They are all opening/closing.
What you probably want to do is move the <Model>
component outside the map so there is only one. Then you want the single model to show the currently selected / chosen item. To do that, rename open
to selectedItem
and setSelectedItem
. When someone clicks the button, you set the "selected item" to that button's item. e.g. <a onClick={()=>setSelectedItem(item)} ...
. And to close the model, set the selectedItem back to undefined.
Then only show the model if selectedItem !== undefined
, and within the model where you have item
use selectedItem
instead.
That should do the trick.