You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在基于Unsplash API的React图片画廊中实现点击打开详情Modal

实现图片点击打开详情Modal的解决方案

问题现状

当前已完成图片画廊基础布局,点击图片卡片时无法打开对应详情Modal,核心问题:

  • Images组件未正确设置状态控制Modal显示/隐藏,也未传递选中图片的详情数据
  • Modal组件未接收props,无法渲染动态内容,显示逻辑未绑定状态

具体修改步骤

1. 调整Images组件

修改状态管理和点击事件逻辑,传递选中图片数据给Modal:

import React from 'react'
import styled from 'styled-components';
import ImgCard from './ImgCard';
import axios from "axios";
import { useState , useEffect } from "react";
import { useSelector } from 'react-redux';
import Modal from './Modal';

const Container = styled.div`
margin-top: 1rem;
column-count: 3;
column-width: 33%;

@media(max-width:1000px){
  column-count:2;
  column-width:50%;
}

@media(max-width:768px){
  column-count:1;
  column-width:100%;
}
`;

const ImgGallery = styled.div``;

const Images = () => {
    let text = useSelector((state) => state.text);
    const [image, setImage] = useState([]);

    const searchURL = `https://api.unsplash.com/search/photos?page=1&query=${text}&per_page=5&client_id=${process.env.REACT_APP_UNSPLASH_API_KEY}` 
    const url = `https://api.unsplash.com/photos/?client_id=${process.env.REACT_APP_UNSPLASH_API_KEY}&per_page=5&page=1`

    useEffect(()=>{
        setImage([]);
        if(text === ''){
        axios.get(url).then((response)=>{
           setImage(response.data);
          }).catch((err)=>{
              console.log(err);
          })
        }else{
          axios.get(searchURL).then((response)=>{
            setImage(response.data.results);
           }).catch((err)=>{
               console.log(err);
           })
        }
      },[url,text]);
    
    // 替换index状态为直接存储选中的图片对象,更直观
    const [openModal, setOpenModal] = useState(false);
    const [selectedImage, setSelectedImage] = useState(null);

    // 点击图片时记录选中图片并打开Modal
    const showModal = (img) => {
        setSelectedImage(img);
        setOpenModal(true);
    }

    // 关闭Modal的回调函数,传给子组件
    const closeModal = () => {
        setOpenModal(false);
        setSelectedImage(null);
    }

  return (
      <Container>
        {/* 传递Modal所需的状态和数据 */}
        <Modal 
          isOpen={openModal} 
          selectedImage={selectedImage} 
          onClose={closeModal} 
        />
         {  
            image.map((item)=>( 
            <ImgGallery key={item.id}>
                {/* 点击时传递当前图片对象 */}
                <ImgCard 
                  link={item.urls.full} 
                  user={item.user} 
                  likes={item.likes} 
                  onClick={()=>showModal(item)} 
                />
            </ImgGallery>
            ))
         }
    </Container>
  )
}

export default Images

修改说明:

  • 将index状态替换为selectedImage,直接存储选中的图片对象,避免数组索引变化导致的错误
  • 完善showModal函数,接收点击的图片对象并更新状态
  • 添加closeModal函数,用于子组件关闭Modal时更新状态
  • 给Modal组件传递isOpen、selectedImage和onClose三个props

2. 修改Modal组件

接收props并渲染动态内容,绑定显示/隐藏逻辑:

import React from 'react'
import styled from 'styled-components';
import ThumbUpIcon from '@mui/icons-material/ThumbUp';
import CloseIcon from '@mui/icons-material/Close';

// 根据isOpen props控制显示/隐藏
const Container = styled.div`
position: absolute;
top: 0;
height:95vh;
border: 1px solid lightgrey;
border-radius: 0.5rem;
overflow: hidden;
display: ${({ isOpen }) => (isOpen ? 'flex' : 'none')};
margin: 1rem;
align-items: center;
background: white;
z-index: 10;
`;

const Image = styled.img`
flex: 1;
object-fit: cover;
width: 100%;
height:100%;
`;

const Details = styled.div`
position: relative;
flex: 1;
display: flex;
flex-direction: column;
gap: 2rem;
padding: 1rem;
align-items: flex-start;
`;

const User = styled.div`
display: flex;
align-items: center;
gap: 0.8rem;
`;

const UserDetails = styled.div`
display: flex;
width:100%;
align-items:center;
justify-content: space-between;
padding: 0rem 1rem;
`;

const UserInfo = styled.div`
display: flex;
flex-direction: column;
`;

const UserImage = styled.img`
width: 3rem;
height: 3rem;
border-radius: 50%;
`;

const Likes = styled.div`
display: flex;
align-items: center;
gap: 0.5rem;
`;

const LikesCount = styled.p``;

const Name = styled.p`
font-weight: 600;
`;

const UserName = styled.p`
color:gray;
`;

const ImageDesc = styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
`;

const Close = styled.div`
position: absolute;
cursor: pointer;
top: 1rem;
right: 2rem;
`;

const Desc = styled.p``;
const AltDesc = styled.p``;
const Date = styled.p``;

// 接收props
const Modal = ({ isOpen, selectedImage, onClose }) => {
  // 如果没有选中图片,直接返回null
  if (!selectedImage) return null;

  // 格式化日期:Unsplash返回的created_at字段
  const formatDate = (dateString) => {
    const date = new Date(dateString);
    return date.toLocaleDateString('en-US', {
      day: 'numeric',
      month: 'long'
    });
  }

  return (
    <Container isOpen={isOpen}>
        {/* 渲染选中图片的高清链接 */}
        <Image src={selectedImage.urls.regular} alt={selectedImage.alt_description} />
        <Details>
        <Close onClick={onClose}>
            <CloseIcon fontSize='large' />
        </Close>
        <UserDetails>
              <User>
                  {/* 渲染用户头像 */}
                  <UserImage src={selectedImage.user.profile_image.medium} />
                 <UserInfo>
                    {/* 渲染用户名 */}
                    <Name>{selectedImage.user.name}</Name>
                    <UserName>@{selectedImage.user.username}</UserName>
                </UserInfo>
             </User>
             <Likes>
                 {/* 渲染点赞数 */}
                 <LikesCount>{selectedImage.likes.toLocaleString()}</LikesCount>
                 <ThumbUpIcon fontSize='medium' />
             </Likes>
        </UserDetails>
        <ImageDesc>
            <Desc>Description</Desc>
            {/* 渲染图片描述,没有则显示默认文本 */}
            <AltDesc>
              {selectedImage.alt_description || 'No description available'}
            </AltDesc>
            {/* 渲染图片创建日期 */}
            <Date>
              {formatDate(selectedImage.created_at)}
            </Date>
        </ImageDesc>
        </Details>
    </Container>
  )
}

export default Modal

修改说明:

  • 给Container添加动态样式,根据isOpenprops切换显示状态
  • 接收isOpen、selectedImage、onClose三个props
  • 将所有静态内容替换为selectedImage中的动态数据,包括图片、用户信息、点赞数、描述、日期等
  • 添加日期格式化函数,处理Unsplash返回的时间字段
  • 关闭按钮绑定onClose回调,点击关闭Modal
  • 添加空值判断,避免未选中图片时渲染错误

效果验证

完成修改后:

  • 点击任意图片卡片,会打开包含该图片详情的Modal
  • 点击关闭按钮可隐藏Modal
  • Modal内的所有内容都会与选中的图片动态关联

内容的提问来源于stack exchange,提问作者Nilay Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 07:37:02