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

React映射列表中如何为当前项的前后元素分配指定类名?

问题

在React中通过数组映射渲染元素列表,已通过useState跟踪当前激活项索引,点击按钮可切换索引。需要基于当前激活索引,为上一个、当前、下一个元素分配特定类名,期望类名结构如下:

<div classname="project inactive">
<div classname="project inactive prev">
<div classname="project active current">
<div classname="project inactive next">
<div classname="project inactive">
</div>

当前点击事件和状态切换逻辑正常,仅需实现类名的动态分配与更新。现有代码如下:

import { useEffect, useRef, useState } from "react"
import ArrowLeft from "../../../../assets/img/ArrowLeft"
import ArrowRight from "../../../../assets/img/ArrowRight"
import projectsData from "../../../../utils/projects.json"

export default function ProjectsNew() {
  // const { currentSection } = useContext(CurrentSectionContext)
  const [projects, setProjects] = useState([])
  const projectsRef = useRef(null)
  let [activeIndex, setActiveIndex] = useState(0)

  useEffect(() => {
    const prevIndex =
    activeIndex - 1 >= 0 ? activeIndex - 1 : projects.length - 1
    
    const nextIndex =
    activeIndex + 1 <= projects.length - 1 ? activeIndex + 1 : 0

    setProjects(projectsData.projects)
  }, [projects, activeIndex])

  const handleNextClick = () => {
    if (activeIndex + 1 <= projects.length - 1) {
      setActiveIndex(activeIndex + 1)
    } else {
      setActiveIndex(0)
    }
  }

  const handlePrevClick = () => {
    if (activeIndex - 1 >= 0) {
      setActiveIndex(activeIndex - 1)
    } else {
      setActiveIndex(projects.length - 1)
    }
  }

  const setActiveClass = (index) => {
    if (activeIndex === index) {
      return " active"
    } else {
      return " inactive"
    }
  }

  return (
    <>
      <div ref={projectsRef} className="projects_wrapper ">
        {projects.map((project, index) => (
          <div
            data-index={index}
            className={`project ${setActiveClass(index)}`}>
            <img className="project_img" src={project.url} alt="." />
            <div className="project_description">
              <p className="project_description_text">
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
                enim ad minim veniam, quis nostrud exercitation ullamco laboris
                nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
                in reprehenderit in voluptate velit esse cillum dolore eu fugiat
                nulla pariatur. Excepteur sint occaecat cupidatat non proident,
                sunt in culpa qui officia deserunt mollit anim id est laborum.
              </p>
            </div>
            <h2 className="project_title">{project.title}</h2>
            <div className="project_btns">
              <div className="btn_prev" onClick={() => handlePrevClick()}>
                <ArrowLeft />
              </div>
              <div className="btn_next" onClick={() => handleNextClick()}>
                <ArrowRight />
              </div>
            </div>
          </div>
        ))}
      </div>
    </>
  )
}

解决方案

  1. 优化状态初始化:直接将projects的初始值设为projectsData.projects,避免在useEffect中重复赋值,同时消除原useEffect因依赖问题导致的无限循环风险。
  2. 动态计算元素类名:编写一个函数,根据当前索引与遍历项的索引,实时判断并返回对应的类名,无需提前存储prev/next索引。
  3. 简化类名逻辑:在映射渲染时,直接调用类名计算函数,为对应元素添加prev、current、next类名。

修改后的完整代码

import { useRef, useState } from "react"
import ArrowLeft from "../../../../assets/img/ArrowLeft"
import ArrowRight from "../../../../assets/img/ArrowRight"
import projectsData from "../../../../utils/projects.json"

export default function ProjectsNew() {
  // const { currentSection } = useContext(CurrentSectionContext)
  const [projects] = useState(projectsData.projects)
  const projectsRef = useRef(null)
  const [activeIndex, setActiveIndex] = useState(0)

  const handleNextClick = () => {
    setActiveIndex(prev => prev + 1 >= projects.length ? 0 : prev + 1)
  }

  const handlePrevClick = () => {
    setActiveIndex(prev => prev - 1 < 0 ? projects.length - 1 : prev - 1)
  }

  const getItemClasses = (index) => {
    const classes = ["project"]
    // 计算循环的上一个和下一个索引
    const prevIndex = activeIndex - 1 >= 0 ? activeIndex - 1 : projects.length - 1
    const nextIndex = activeIndex + 1 < projects.length ? activeIndex + 1 : 0

    if (index === activeIndex) {
      classes.push("active", "current")
    } else if (index === prevIndex) {
      classes.push("inactive", "prev")
    } else if (index === nextIndex) {
      classes.push("inactive", "next")
    } else {
      classes.push("inactive")
    }
    return classes.join(" ")
  }

  return (
    <>
      <div ref={projectsRef} className="projects_wrapper ">
        {projects.map((project, index) => (
          <div
            key={index} // 添加key属性,符合React列表渲染规范
            data-index={index}
            className={getItemClasses(index)}>
            <img className="project_img" src={project.url} alt={project.title} />
            <div className="project_description">
              <p className="project_description_text">
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
                enim ad minim veniam, quis nostrud exercitation ullamco laboris
                nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
                in reprehenderit in voluptate velit esse cillum dolore eu fugiat
                nulla pariatur. Excepteur sint occaecat cupidatat non proident,
                sunt in culpa qui officia deserunt mollit anim id est laborum.
              </p>
            </div>
            <h2 className="project_title">{project.title}</h2>
            <div className="project_btns">
              <div className="btn_prev" onClick={handlePrevClick}>
                <ArrowLeft />
              </div>
              <div className="btn_next" onClick={handleNextClick}>
                <ArrowRight />
              </div>
            </div>
          </div>
        ))}
      </div>
    </>
  )
}

关键改动说明

  • 移除了冗余的useEffect,直接初始化projects状态,避免不必要的重渲染。
  • 简化了handleNextClick和handlePrevClick函数,使用函数式更新获取最新状态值,逻辑更简洁。
  • 新增getItemClasses函数,实时计算每个元素的类名,根据索引判断是否为当前、上一个或下一个元素,返回拼接后的类名字符串。
  • 为列表项添加了key属性,符合React列表渲染的最佳实践。
  • 优化了图片的alt属性,使用项目标题替代占位符,提升可访问性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 19:25:20