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

React+Antd项目求助:点击用户按钮无法在Modal显示对应信息

问题分析与解决方案

核心问题

  1. 重复渲染Modal:每个用户列表项都渲染了独立的Modal组件,且共用同一个isModalOpen状态。点击按钮时所有Modal都会触发显示,受DOM渲染顺序影响,最终只会展示最后一个用户的Modal内容,无法匹配点击目标用户。
  2. 缺少当前用户状态:没有存储点击的目标用户数据,Modal无法获取对应用户的信息。
  3. 分页逻辑错误:nextUser每次加5,但filteredUsers取的是currentPage到currentPage+6的用户,会导致用户重复显示,且最后一页无法正确展示剩余用户。

修复方案

  1. 将Modal从列表项中移出,仅在父组件中渲染一个全局Modal。
  2. 添加selectedUser状态,存储当前点击的用户信息。
  3. 修改openModal方法,点击时传入当前用户并更新状态。
  4. 修复分页逻辑,确保每页显示6条数据,且最后一页能完整展示剩余用户。

修改后的完整代码

import { Modal } from "antd";
import 'antd/dist/antd.css';
import { useEffect, useState } from "react";
import { userApi } from "../api/userApi";
import { Usuario } from "../interfaces/fetchAllUserResponse";

export const List = () => {
  const [users, setUsers] = useState<Usuario[]>([]);
  const [currentPage, setCurrentPage] = useState(0);
  const [isModalOpen, setIsModalOpen] = useState(false);
  // 新增状态存储当前选中的用户
  const [selectedUser, setSelectedUser] = useState<Usuario | null>(null);

  useEffect(() => {
    userApi.get<Usuario[]>('/default/techJobMission')
      .then(resp => {
        setUsers(resp.data);
      })
      .catch(console.log);
  }, []);

  // 修正分页切片逻辑,每页固定6条数据
  const filteredUsers = (): Usuario[] => {
    const pageSize = 6;
    return users.slice(currentPage * pageSize, (currentPage + 1) * pageSize);
  };

  // 计算总页数
  const totalPages = Math.ceil(users.length / 6);

  const nextUser = () => {
    // 限制页码不超过最后一页
    if (currentPage < totalPages - 1) {
      setCurrentPage(currentPage + 1);
    }
  };

  const prevUser = () => {
    if (currentPage > 0) {
      setCurrentPage(currentPage - 1);
    }
  };

  // 打开Modal时保存当前用户信息
  const openModal = (user: Usuario) => {
    setSelectedUser(user);
    setIsModalOpen(true);
  };

  const handleOk = () => {
    setIsModalOpen(false);
    setSelectedUser(null); // 关闭时清空选中状态
  };

  const handleCancel = () => {
    setIsModalOpen(false);
    setSelectedUser(null);
  };

  const renderItem = ({ _id, firstName, lastName, ticket, present }: Usuario) => {
    return (
      <tr key={_id}>
        <td>
          {(present ? <img className="ticket" src="icons/ticket-green.svg" /> : <img className="ticket" src="icons/ticket-red.svg" />)}
        </td>
        <td className="user">
          <p className="encabezado">{firstName} {lastName}</p>
          {(present ? <p className="estado">Ha entrado</p> : <p className="estado">No ha entrado</p>)}
        </td>
        <td className="id-user">
          <p className="encabezado2">ID</p>
          <p className="estado">{_id}</p>
        </td>
        <td className="ticket-td">
          <p className="encabezado2">Nº de ticket</p>
          <p className="estado">{ticket + 1}</p>
        </td>
        <td>
          <button onClick={() => openModal({ _id, firstName, lastName, ticket, present })} className="btn-modal">
            <img src="icons/menu-modal.svg" />
          </button>
        </td>
      </tr>
    );
  };

  return (
    <>
      <table className="table">
        <tbody>
          {filteredUsers().map(renderItem)}
        </tbody>
      </table>
      <br />
      <button onClick={prevUser} className="paginacion" disabled={currentPage === 0}>
        <img src="icons/anterior.svg" /> Anterior
      </button>
      <button onClick={nextUser} className="paginacion" disabled={currentPage === totalPages - 1}>
        Siguiente <img src="icons/siguiente.svg" />
      </button>

      {/* 全局唯一的Modal,基于selectedUser渲染内容 */}
      <Modal open={isModalOpen} onOk={handleOk} onCancel={handleCancel} title="用户详情">
        {selectedUser && (
          <div>
            <p>姓名:{selectedUser.firstName} {selectedUser.lastName}</p>
            <p>ID:{selectedUser._id}</p>
            <p>票号:{selectedUser.ticket + 1}</p>
            <p>状态:{selectedUser.present ? 'Ha entrado' : 'No ha entrado'}</p>
          </div>
        )}
      </Modal>
    </>
  );
};

关键修改说明

  • 全局Modal:避免重复渲染多个Modal,确保每次仅展示一个弹窗。
  • selectedUser状态:点击按钮时保存当前用户,Modal根据该状态渲染对应信息,实现点击用户与弹窗内容的匹配。
  • 分页逻辑优化:改为按页码计算切片范围,添加页码边界判断,同时给分页按钮添加disabled属性优化交互体验。
  • 状态清空:Modal关闭时清空selectedUser,避免下次打开弹窗时显示旧数据。

内容的提问来源于stack exchange,提问作者Agustin Marin Posadas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:10:46