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

React触发模态框报错Cannot read property 'classList' of undefined咨询

问题原因

你遇到的报错类型错误:无法读取未定义的属性'classList'核心是Bootstrap原生模态框触发逻辑和React状态更新/渲染时序不匹配,具体有两个直接诱因:

  1. 触发时序冲突:你点击按钮时同时执行两个操作:一是靠data-bs-toggle触发原生Bootstrap模态框打开,二是dispatch更新store里的报价单ID。原生JS的事件触发优先级远高于React的状态更新、重渲染流程,此时你设置的条件渲染的模态框还没挂载到DOM上,Bootstrap JS找不到data-bs-target指定的DOM元素,操作不存在元素的classList就触发了报错。
  2. ID不匹配:按钮上的data-bs-target是#modal-pdf-开头的动态值,但模态框的ID绑定的是modalTitle这个空state,你全程没有给modalTitle赋值,就算模态框完成渲染,ID也对应不上,Bootstrap仍然找不到目标元素。

解决方案

推荐优先用React状态控制模态框显示,完全避开原生Bootstrap的自动触发逻辑,适配性最高:

步骤1:移除原生触发属性

删除按钮上的data-bs-toggle和data-bs-target属性,不再依赖原生Bootstrap的自动模态框触发逻辑,修改后按钮代码:

<button type="button"
        onClick={() => {
          dispatch(sendEstimateToShow(estimate.id))
          setShowModal(true)
          // 这里可以同步给modalTitle赋值,保证后续如果需要用ID的话和按钮生成规则一致
          setModalTitle(`modal-pdf-${estimate.estimate_name.toLowerCase().replaceAll(' ', '-').replaceAll('°', '-')}`)
        }}
        className="btn btn-primary">
    <i className="bi bi-eye-fill"></i>
</button>

步骤2:新增状态控制模态框显示

在组件内新增控制模态框显示的状态:

const [showModal, setShowModal] = useState(false)

步骤3:调整模态框渲染逻辑

修改模态框的渲染条件和样式,用React状态控制显隐:

const estimateToShow = useSelector(state => state.estimatesReducer.estimateToShow)
const estimateToShowData = estimates.filter(estimate => estimate.id === estimateToShow)

{showModal && !isEmpty(estimateToShowData) && (
    // 显示时加上show和d-block类,符合Bootstrap模态框显示的样式要求
    <div className="modal show d-block"
         id={modalTitle}
         tabIndex="-1"
         aria-hidden={!showModal}>
        <div className="modal-dialog modal-dialog-centered modal-lg">
            <div className="modal-content">
                <div className="modal-header">
                    <h5 className="modal-title"
                        id="exampleModalLabel">{estimateToShowData[0].estimate_name}</h5>
                    <button type="button" className="btn-close"
                            onClick={() => {
                              setLoadPdf(false)
                              setShowModal(false)
                              // 可选:关闭时清空store里的报价单ID,避免残留
                              dispatch(sendEstimateToShow(null))
                            }}
                            aria-label="Close"></button>
                </div>
                <div className="modal-body d-flex justify-content-center flex-column">
                    {
                        loadPdf && (
                            <PDFViewer height={"500px"}>
                                <EstimateTemplatePdf currentEstimate={estimateToShowData[0]}/>
                            </PDFViewer>
                        )
                    }
                </div>
                <div className="modal-footer">
                    <button type="button"
                            onClick={() => {
                              setLoadPdf(false)
                              setShowModal(false)
                              dispatch(sendEstimateToShow(null))
                            }}
                            className="btn btn-secondary">关闭
                    </button>
                    <a
                        href={instance.url}
                        className={"btn btn-primary"}
                        download="devis.pdf">
                        下载报价单
                    </a>
                </div>
            </div>
        </div>
    </div>
)}
// 可选:加上模态框蒙层
{showModal && <div className="modal-backdrop show"></div>}

替代方案(坚持用原生Bootstrap触发)

如果不想改动原生触发逻辑,按以下步骤调整:

  1. 移除模态框的条件渲染,一直渲染模态框DOM,没有数据时内容显示加载态即可,保证DOM初始就存在
  2. 提前给modalTitle赋值,保证和按钮的data-bs-target生成规则完全一致
  3. 用useEffect监听estimateToShow变化,拿到数据后再手动调用Bootstrap模态框实例的show方法触发显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 06:24:02