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

React+NextJS:点击角色图标让模态框展示对应角色详情

问题:点击角色图标后模态框展示所有角色信息,需改为仅展示对应角色详情

我是React新手,用NextJS开发。现在有个角色数组,用map渲染每个角色的名称和描述。想实现点击角色图标时,模态框只显示该角色的职责和要求,但现在模态框会把所有角色的内容都展示出来,不知道怎么定位特定角色的属性,求帮助。

角色数组示例

const roles = [
    {
        id: 1,
        name: 'First Role',
        description: 'ipsum description', 
        responsibilities: 'ipsum responsibilities',
        requirements: "ipsum requirement",
    },
    {
        id: 2,
        name: 'Fourth Role',
        description: 'ipsum description', 
        responsibilities: 'ipsum responsibilities',
        requirements: "ipsum requirement",
    },
    {
        id: 3,
        name: 'Third Role',
        description: 'ipsum description',
        responsibilities: 'ipsum responsibilities',
        requirements: "ipsum requirement",
    },
]

核心问题分析

当前代码的问题很明确:

  1. 模态框内直接遍历所有角色,没有区分当前点击的目标角色
  2. 自定义useModal仅管理了模态框的开关状态,没有存储选中角色的信息

解决方案:分步修改代码

1. 升级useModal Hook,支持存储选中角色

修改Hook,新增状态保存选中角色,拆分开关方法以便传入角色参数:

import { useState } from 'react';

// 若有角色类型定义可引入,无则省略
// import { Role } from './your-types';

export default function useModal() {
  const [isOpen, setIsOpen] = useState(false);
  const [selectedRole, setSelectedRole] = useState<Role | null>(null);

  // 打开模态框并传入选中角色
  const open = (role: Role) => {
    setSelectedRole(role);
    setIsOpen(true);
  };

  // 关闭模态框并清空选中角色
  const close = () => {
    setIsOpen(false);
    setSelectedRole(null);
  };

  return {
    isOpen,
    selectedRole,
    open,
    close
  };
}

2. 修改Careers页面组件,传递选中角色到模态框

更新点击事件逻辑,调用open方法传入当前角色,同时模态框仅渲染选中角色的信息:

export default function Careers() {
  const { isOpen, selectedRole, open, close } = useModal()
  
  return (
    <>
      <Head>
        <title>Careers</title>
        <meta name='description' content='Careers' />
      </Head>
      <HeroGeneric heading='Careers' message="" />

      <div className=" py-24 sm:py-32">
        <div className="mx-auto max-w-7xl px-6 lg:px-8">
          <div className="mx-auto max-w-2xl lg:text-center">
            <h2 className="text-base font-semibold leading-7 text-indigo-600">Open Roles</h2>
            <p className="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
              How you can make a difference
            </p>
            <p className="mt-6 text-lg leading-8 text-gray-600">
              Quis tellus eget adipiscing convallis sit sit eget aliquet quis. Suspendisse eget egestas a elementum
              pulvinar et feugiat blandit at. In mi viverra elit nunc.
            </p>
          </div>
          <div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-4xl">
            <dl className="grid max-w-xl grid-cols-1 gap-x-8 gap-y-10 lg:max-w-none lg:grid-cols-2 lg:gap-y-16">
              {roles.map((role) => (
                <div key={role.id} className=" glass relative pl-16">
                  <dt className="text-base m-2 font-semibold leading-7 text-gray-900">
                    <div className="absolute left-0 top-0 ml-2 mt-2 flex h-10 w-10 items-center justify-center rounded-lg bg-taublue">
                      {/* 点击时传递当前角色给open方法 */}
                      <span onClick={() => open(role)}>
                        <Image
                          src={roleIcon}
                          className="h-6 w-6 text-white"
                          alt={role.name}
                          height={"24"} width={"24"}
                        />
                      </span>
                    </div>
                    {role.name}
                  </dt>
                  <dd className="mt-2 mr-2 mb-2 text-base leading-7 text-gray-600">{role.description}</dd>
                </div>
              ))}
            </dl>
          </div>
        </div>
        <TestModal
          isOpen={isOpen}
          toggle={close}
        >
          {/* 仅渲染选中的角色信息 */}
          {selectedRole && (
            <div className="glass relative pl-16">
              <dt className="text-base m-2 font-semibold leading-7 text-gray-900">
                {selectedRole.name}
              </dt>
              <dd className="mt-2 mr-2 mb-2 text-base leading-7 text-gray-600">
                <strong>职责:</strong>{selectedRole.responsibilities}
              </dd>
              <dd className="mt-2 mr-2 mb-2 text-base leading-7 text-gray-600">
                <strong>要求:</strong>{selectedRole.requirements}
              </dd>
            </div>
          )}
        </TestModal>
      </div>
    </>
  )
}

3. (可选)更新Modal组件类型定义

如果需要更严谨的类型检查,可更新Modal的props类型(不修改也不影响运行):

import React, { ReactNode } from 'react';

interface ModalType {
  children?: ReactNode;
  isOpen: boolean;
  toggle: () => void;
}

export default function Modal(props: ModalType) {
  return (
    <>
      {props.isOpen && (
        <div className='modal-overlay' onClick={props.toggle}>
          <div onClick={(e) => e.stopPropagation()} className='modal-box'>
            {props.children}
          </div>
        </div>
      )}
    </>
  );
}

关键改动说明

  • 在useModal中新增selectedRole状态,专门存储当前点击的角色对象
  • 将原toggle拆分为open(接收角色参数)和close方法,分别处理打开/关闭逻辑
  • 页面点击角色图标时,调用open(role)将当前角色传入Hook
  • 模态框内不再遍历所有角色,而是根据selectedRole渲染对应内容

修改完成后,点击不同角色的图标,模态框就会只显示该角色的职责和要求了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:20:59