首页 > 解决方案 > React Material UI Cards w/Modal

问题描述

I'm trying to configure this React JS / Material UI modal dialog so that when the user clicks on the card, it opens a corresponding full-sized image (with title and subtitle). Data for each card is mapped from a JSON file (via AXIOS).

I can get the modal window to open, but it is showing all of the card images in the modal and they are stacked on top of each other. The console.log("SELECTED CAMPAIGN: ", selectedCampaign) code inside the handleOpen() function is one click behind...it actually logs the object that was selected prior to the current click event.

I'm relatively new to functional components and hooks, so I know that I am making simple and fundamental mistakes...please help me figure out the proper way to set this up:

const CampaignItems = ({campaigns, loading}) => {
    const classes = useStyles();

    const [open, setOpen] = useState(false);
    const [selectedCampaign, setSelectedCampaign] = useState();

    const handleOpen = (campaign) => {
        setSelectedCampaign(campaign);
        console.log("SELECTED CAMPAIGN: ", selectedCampaign);
        setOpen(true);
    };

    const handleClose = () => {
        setOpen(false);
    };

..................


<div>
                <GridContainer>
                    {campaigns && search(campaigns).map((campaign) => (
                        <GridItem key={campaign.id} xs={12} sm={6} md={4}>
                            <Card className={classes.root}>
                                <CardActionArea>
                                    <CardMedia
                                        component="img"
                                        alt={campaign.alt}
                                        height="140"
                                        image={campaign.image}
                                        title={campaign.title}
                                        onClick={() => handleOpen(campaign)}
                                    />
                                    <CardContent>
                                    <Typography gutterBottom variant="h5" component="h2">
                                        {campaign.title}
                                    </Typography>
                                        <Typography variant="body2" color="textSecondary" component="p">
                                            {campaign.subtitle}
                                        </Typography>
                                    </CardContent>
                                </CardActionArea>
                                <CardActions>
                                    <IconButton
                                        size="medium" 
                                        color="primary" 
                                        aria-label="More Information"
                                        onClick={() => handleOpen(campaign)}
                                    >
                                        <InfoIcon />
                                    </IconButton>

                                    <Modal
                                        className={classes.modal}
                                        open={open}
                                        onClose={handleClose}
                                        closeAfterTransition
                                        BackdropComponent={Backdrop}
                                        BackdropProps={{
                                            timeout: 500
                                        }}
                                    >
                                        <Fade 
                                            in={open}
                                        >
                                            <div className={classes.paper}>
                                                <h6>{campaign.title}</h6>
                                                <p>{campaign.subtitle}</p>
                                                <img src={campaign.image} />
                                            </div>
                                        </Fade>
                                    </Modal>

                                </CardActions>
                            </Card>
                        </GridItem>
                    ))}
                </GridContainer>
            </div>

..................

标签: reactjsmaterial-uimodal-dialogcard

解决方案


您的问题似乎是您仅使用一个open状态来触发您的模式打开,因此它们都被同时触发打开。

我建议改为使用selectedCampaign您正在与之交互的卡片,并使用广告系列 ID 来匹配要打开的模式。

const CampaignItems = ({campaigns, loading}) => {
  ...

  const [selectedCampaign, setSelectedCampaign] = useState(null);

  const handleOpen = (campaign) => () => {
    setSelectedCampaign(selectedCampaign => 
      selectedCampaign.id === campaign.id ? null : campaign
    );
  };

  const handleClose = () => {
    setSelectedCampaign(null);
  };

  ...


  <div>
    <GridContainer>
      {campaigns && search(campaigns).map((campaign) => (
        <GridItem key={campaign.id} xs={12} sm={6} md={4}>
          <Card className={classes.root}>
            <CardActionArea>
              <CardMedia
                ...
                onClick={handleOpen(campaign)}
              />
              ...
            </CardActionArea>
            <CardActions>
              <IconButton
                ...
                onClick={handleOpen(campaign)}
              >
                ...
              </IconButton>

              <Modal
                ...
                open={selectedCampaign.id === campaign.id} // <-- check id match
                onClose={handleClose}
                ...
              >
                ...
              </Modal>

            </CardActions>
          </Card>
        </GridItem>
      ))}
    </GridContainer>
  </div>

  ...

推荐阅读