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

React中如何用单一函数实现多卡片图片切换的优化方案

问题描述

我正在React应用中构建一个包含3张卡片的模块,每张卡片含一张图片,图片下方有2个按钮,点击可切换默认显示的图片。目前已实现功能,但多函数方案并非最佳实践。我创建了存储城市数据的JSON文件,基于城市名称和ID导入数据,现寻求高效方案:用单个函数处理所有卡片的图片切换,且支持后续添加更多图片或按钮。现有实现代码与数据结构如下:

// 原切换函数
const changeCity1 = () => {
  if(scenesData.paris[0].id == 1 && scenesData.paris[0].city == "paris") {
    imageRef1.current.src = scenesData.paris[0].imageURL1;
  }
}

const changeCity2 = () => {
  if(scenesData.paris[1].id == 2 && scenesData.paris[1].city == "paris") {
    imageRef1.current.src = scenesData.paris[1].imageURL2;
  } 
}

const changeCity3 = () => {
  if(scenesData.tejMahal[0].id == 1 && scenesData.tejMahal[0].city == "tejMahal") {
    imageRef2.current.src = scenesData.tejMahal[0].imageURL1;
  } 
}

const changeCity4 = () => {
  if(scenesData.tejMahal[1].id == 2 && scenesData.tejMahal[1].city == "tejMahal") {
    imageRef2.current.src = scenesData.tejMahal[1].imageURL2;
  } 
}
// 原卡片渲染代码
<div className="item-img">
  <a className="imago wow">
    <img ref={imageRef1} alt="image1" />
    <div className="item-img-overlay"></div>
  </a>
</div>
<div className="cont">
  <h6>paris</h6>
  <span>
    <div className="text-center">
      <button className="nb butn light mt-30 full-width" onClick={changeColor1}>
        <span className="ls3 text-u">1</span>
      </button>
      <button className="nb butn light mt-30 full-width" onClick={changeColor2}>
        <span className="ls3 text-u">2</span>
      </button>
    </div>
  </span>
</div>

<div className="item-img">
  <a className="imago wow">
    <img ref={imageRef2} alt="image2" />
    <div className="item-img-overlay"></div>
  </a>
</div>
<div className="cont">
  <h6>Energies of Love</h6>
  <span>
    <div className="text-center">
      <button className="nb butn light mt-30 full-width" onClick={changeColor3}>
        <span className="ls3 text-u">1</span>
      </button>
      <button className="nb butn light mt-30 full-width" onClick={changeColor4}>
        <span className="ls3 text-u">2</span>
      </button>
    </div>
  </span>
</div>
// 原JSON数据
{
  "paris": [
    {     
      "id": 1,
      "city": "paris",
      "imageURL1": "www.example.com"
    },
    {
      "id": 2,
      "city": "paris",
      "imageURL2": "www.example.com"
    }
  ],
  "tejMahal": [
    {
      "id": 1,
      "city": "tejMahal",
      "imageURL1": "www.example.com"
    },
    {
      "id": 2,
      "city": "tejMahal",
      "imageURL2": "www.example.com"
    }
  ]
}
高效实现方案

当然存在更高效的实现方式,核心思路是用状态驱动UI、统一切换逻辑、动态渲染卡片,同时优化数据结构以支持扩展性:

1. 优化数据结构

将原JSON中每个城市的分散图片URL改为数组形式,支持任意数量的图片,后续新增图片只需追加数组元素:

{
  "paris": [
    {
      "id": 1,
      "city": "paris",
      "images": ["www.example.com/paris-1.jpg", "www.example.com/paris-2.jpg"]
    }
  ],
  "tejMahal": [
    {
      "id": 1,
      "city": "tejMahal",
      "images": ["www.example.com/tej-1.jpg", "www.example.com/tej-2.jpg"]
    }
  ]
}

2. React组件实现

import { useState } from 'react';
import scenesData from './your-data-file.json';

const CityCards = () => {
  // 初始化每个城市的默认图片索引(默认显示第一张)
  const [currentImageIndex, setCurrentImageIndex] = useState(() => {
    return Object.keys(scenesData).reduce((acc, cityName) => {
      acc[cityName] = 0;
      return acc;
    }, {});
  });

  // 通用切换函数:接收城市名和目标图片索引,统一处理所有卡片的图片切换
  const handleImageSwitch = (cityName, targetIndex) => {
    setCurrentImageIndex(prevState => ({
      ...prevState,
      [cityName]: targetIndex
    }));
  };

  return (
    <div className="cards-container">
      {/* 动态遍历所有城市数据,生成卡片 */}
      {Object.entries(scenesData).map(([cityName, cityEntries]) => {
        const cityData = cityEntries[0]; // 取每个城市的主数据条目
        const currentImgUrl = cityData.images[currentImageIndex[cityName]];

        return (
          <div key={cityName} className="card">
            <div className="item-img">
              <a className="imago wow">
                <img src={currentImgUrl} alt={cityName} />
                <div className="item-img-overlay"></div>
              </a>
            </div>
            <div className="cont">
              <h6>{cityName}</h6>
              <span>
                <div className="text-center">
                  {/* 动态生成图片切换按钮,数量与该城市的图片数一致 */}
                  {cityData.images.map((_, index) => (
                    <button
                      key={index}
                      className="nb butn light mt-30 full-width"
                      onClick={() => handleImageSwitch(cityName, index)}
                    >
                      <span className="ls3 text-u">{index + 1}</span>
                    </button>
                  ))}
                </div>
              </span>
            </div>
          </div>
        );
      })}
    </div>
  );
};

export default CityCards;

核心优化点

  • 单一通用函数:handleImageSwitch通过接收城市名和图片索引,统一处理所有卡片的切换逻辑,无需为每个按钮单独编写函数。
  • 状态驱动UI:用React状态管理当前选中的图片索引,避免直接操作DOM,符合React的单向数据流模式,更易于维护。
  • 动态渲染:通过遍历数据自动生成卡片和按钮,后续新增城市或图片只需修改JSON数据,无需修改组件渲染代码。
  • 扩展性强:数据结构改为数组后,支持任意数量的图片,按钮会根据图片数量自动生成,无需额外开发。

内容的提问来源于stack exchange,提问作者David Jay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:15:40