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

React中如何结合路由使用Modal实现列表项查看编辑及删除确认弹窗

React 结合路由实现 Modal 弹窗操作方案

实现思路

你需要的两个功能可以分别按以下逻辑实现,其中查看弹窗支持和路由绑定,删除确认弹窗用内部状态控制即可:

  • 删除确认:点击删除按钮后先打开确认弹窗,用户点击确认后再执行删除接口调用
  • 查看弹窗:支持两种实现方式,可根据业务需要选择:
    • 路由绑定模式:打开弹窗时URL同步更新,刷新后弹窗仍保持打开,支持直接分享URL打开对应详情弹窗
    • 内部状态模式:URL无变化,纯组件内状态控制弹窗显隐,实现成本更低

前置准备

  1. 确保已安装 react-router-dom(推荐v6+版本)
  2. 你可以使用任意UI库的Modal组件(比如Ant Design的Modal、React Bootstrap的Modal),以下示例用通用结构编写,可直接替换为你项目中用的组件
  3. 你原有代码中接口返回值存在 holidays 状态,但渲染用的是 res 状态,缺少 setRes 逻辑,以下代码会先修复这个问题

完整改造代码(路由绑定模式)

第一步:调整路由配置

// 你的路由配置文件中,新增带可选参数的路由,指向同一个列表组件
{
  path: '/holiday',
  element: <AddHolidayForm />,
  children: [
    // 可选参数id,匹配查看弹窗的路由
    { path: 'view/:id', element: <AddHolidayForm /> }
  ]
}

第二步:改造组件代码

import { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import axios from 'axios';
// 引入你用的Modal组件,这里以React Bootstrap为例,可替换为其他UI库的Modal
import { Modal, Button, Table } from 'react-bootstrap';
import { FaEye, FaTrashAlt } from 'react-icons/fa';

const AddHolidayForm = () => {
  // 路由相关API
  const { id: viewId } = useParams();
  const navigate = useNavigate();
  // 原有业务状态
  const [holidays, setHolidays] = useState([]);
  const [page, setPage] = useState(0); // 补全你原有分页参数
  const [rowsPerPage, setRowsPerPage] = useState(10); // 补全你原有分页参数
  // 弹窗相关状态
  const [delModalVisible, setDelModalVisible] = useState(false);
  const [currentDelId, setCurrentDelId] = useState(null);
  // 当前查看的节假日详情
  const [currentViewHoliday, setCurrentViewHoliday] = useState(null);

  useEffect(() => {
    loadHoliday();
  }, []);

  // 路由参数变化时,自动打开/关闭查看弹窗
  useEffect(() => {
    if (viewId && holidays.length) {
      // 从列表中找到对应id的节假日信息,也可以单独调接口查详情
      const holiday = holidays.find(item => item.id === Number(viewId));
      setCurrentViewHoliday(holiday || null);
    } else {
      setCurrentViewHoliday(null);
    }
  }, [viewId, holidays]);

  const loadHoliday = async () => {      
    const res = await axios.post(`http://localhost:.....`, {});
    const list = res.data.reverse();
    setHolidays(list);
    // 修复你原有代码漏写的setRes,这里直接用holidays渲染也可以,不需要多余的res状态
    // setRes(list);
  };

  const deleteHoliday = async () => {
    await axios.delete(`http://..../${currentDelId}`);
    // 关闭删除弹窗
    setDelModalVisible(false);
    setCurrentDelId(null);
    loadHoliday();
  };

  return (
    <div className="container">
      <div className="py-4">                    
        <Table responsive>
          <thead className="thead-dark">
            <tr>
              <th scope="col">#</th>
              <th>Action</th>
              <th scope="col">Name</th>
              <th scope="col">Start Time</th>
              <th scope="col">End Time</th>
            </tr>
          </thead>
          <tbody>
            {holidays.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
              .map((holiday, index) => {
                return (
                  <tr key={holiday.id}>
                    <th scope="row">{index + 1}</th>
                    <td> 
                      <Button 
                        className="btn btn-primary mr-2"
                        onClick={() => navigate(`/holiday/view/${holiday.id}`)}
                      >
                        <FaEye />
                      </Button>
                      <Button
                        className="btn btn-danger"
                        onClick={() => {
                          setCurrentDelId(holiday.id);
                          setDelModalVisible(true);
                        }}              
                      >                                                    
                        <FaTrashAlt />
                      </Button>
                    </td>
                    <td>{holiday.name}</td>
                    <td>{holiday.startTime}</td>
                    <td>{holiday.endTime}</td>
                  </tr>
                )  
              }) 
            }
          </tbody>
        </Table>                          
      </div>

      {/* 删除确认弹窗 */}
      <Modal show={delModalVisible} onHide={() => setDelModalVisible(false)}>
        <Modal.Header closeButton>
          <Modal.Title>确认删除</Modal.Title>
        </Modal.Header>
        <Modal.Body>确定要删除这个节假日吗?删除后无法恢复。</Modal.Body>
        <Modal.Footer>
          <Button variant="secondary" onClick={() => setDelModalVisible(false)}>
            取消
          </Button>
          <Button variant="danger" onClick={deleteHoliday}>
            确认删除
          </Button>
        </Modal.Footer>
      </Modal>

      {/* 查看详情弹窗 */}
      <Modal show={!!currentViewHoliday} onHide={() => navigate('/holiday')}>
        <Modal.Header closeButton>
          <Modal.Title>节假日详情</Modal.Title>
        </Modal.Header>
        <Modal.Body>
          {currentViewHoliday && (
            <div>
              <p>名称:{currentViewHoliday.name}</p>
              <p>开始时间:{currentViewHoliday.startTime}</p>
              <p>结束时间:{currentViewHoliday.endTime}</p>
              {/* 可以加更多详情字段,或者引入编辑表单组件 */}
            </div>
          )}
        </Modal.Body>
        <Modal.Footer>
          <Button variant="secondary" onClick={() => navigate('/holiday')}>
            关闭
          </Button>
        </Modal.Footer>
      </Modal>
    </div>
  );
}

export default AddHolidayForm;

关键逻辑说明

  1. 如果你不需要路由绑定,只需要把查看弹窗的显隐用单独的state比如 viewModalVisible 控制即可,点击查看按钮时直接给 currentViewHoliday 赋值并打开弹窗,不需要调用 navigate 也不需要调整路由配置
  2. 如果详情数据需要单独拉取接口,可以在检测到 viewId 变化的时候调用详情接口,不需要从现有列表里取
  3. 如果要加编辑功能,只需要在查看弹窗里加编辑按钮,或者单独做一个编辑弹窗,逻辑和查看弹窗一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 17:18:02