React项目引入jQuery CDN后仍报Uncaught ReferenceError错误求助
解决React中使用DataTable时「Uncaught ReferenceError: jQuery is not defined」的问题
核心问题分析
你的代码存在两个关键问题导致错误:
- 重复且冲突的jQuery引入:同时通过
import $ from 'jquery'引入npm包版本,又动态加载CDN版本的jQuery。DataTables依赖全局的jQuery变量,但你直接调用的$是模块内的局部变量,且CDN脚本是异步加载的,执行$('#example').DataTable()时全局jQuery可能还未就绪。 - 异步脚本加载未处理顺序与完成状态:动态创建的脚本默认异步加载,你直接在脚本添加到DOM后立刻初始化DataTables,此时jQuery或DataTables脚本可能还未加载完成,自然找不到
jQuery变量。
解决方案一:使用npm管理依赖(推荐,符合React项目规范)
放弃动态加载CDN的方式,直接通过npm安装所需依赖,避免异步加载问题:
- 安装依赖
npm install jquery datatables.net datatables.net-bs5 bootstrap
- 修改组件代码
import React, { useEffect, useState } from "react"; import $ from 'jquery'; import 'datatables.net-bs5'; // 引入DataTables的Bootstrap5适配 import 'bootstrap/dist/css/bootstrap.min.css'; import 'datatables.net-bs5/css/dataTables.bootstrap5.min.css'; const ViewCustomers = ( {fetchCustomers, userData, customerDetail, initialUpdate, updateSuccess} ) => { // 存储DataTable实例,用于卸载时销毁 const [dataTable, setDataTable] = useState(null); useEffect(() => { fetchCustomers(); initialUpdate(); console.log(updateSuccess); }, []); useEffect(() => { // 确保userData存在且表格已渲染后初始化DataTable if (userData && !dataTable) { const table = $('#example').DataTable(); setDataTable(table); } // 组件卸载时销毁DataTable,避免内存泄漏 return () => { if (dataTable) { dataTable.destroy(); } }; }, [userData, dataTable]); // 补充定义缺失的onClick和onSubmit函数 const onClick = (e) => { // 替换为你的点击逻辑 console.log(e.target.name); }; const onSubmit = (e) => { e.preventDefault(); // 替换为你的提交逻辑 }; return userData ? ( <div> <button type="button" className="btn btn-primary" name="create" onClick={onClick}> <i className="bi bi-plus-square-fill"></i>Create </button> <form onSubmit={onSubmit}> <table id="example" className="table table-striped"> <thead> <tr> <th scope="col">Serial</th> <th scope="col">Customer Name</th> <th scope="col">MAC</th> <th scope="col">Action</th> </tr> </thead> <tbody> {userData.map((customer, index) => ( <tr key={customer.id}> <th scope="row">{index + 1}</th> <td>{customer.customer_name}</td> <td>{customer.customer_mac}</td> <td> <button type="submit" name="cid" value={customer.id} className="btn btn-primary" onClick={onClick} >Modify</button> </td> </tr> ))} </tbody> </table> </form> </div> ) : ( <div>Please login first</div> ) }; export default ViewCustomers;
解决方案二:强制使用CDN加载(仅当必须用CDN时)
需要确保脚本按顺序加载完成后再初始化DataTables,可通过Promise封装脚本加载逻辑:
import React, { useEffect } from "react"; // 封装脚本加载为Promise const loadScript = (src) => { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); return script; }); }; // 封装样式加载为Promise const loadStyle = (href) => { return new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = href; link.onload = resolve; link.onerror = reject; document.head.appendChild(link); return link; }); }; const ViewCustomers = ( {fetchCustomers, userData, customerDetail, initialUpdate, updateSuccess} ) => { useEffect(() => { let scripts = []; let styles = []; const initDataTable = async () => { try { // 按顺序加载脚本:先jQuery,再DataTables,再Bootstrap适配 scripts.push(await loadScript("https://code.jquery.com/jquery-3.6.3.js")); scripts.push(await loadScript("https://cdn.datatables.net/1.13.2/js/jquery.dataTables.min.js")); scripts.push(await loadScript("https://cdn.datatables.net/1.13.2/js/dataTables.bootstrap5.min.js")); // 加载样式 styles.push(await loadStyle("https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.2.0/css/bootstrap.min.css")); styles.push(await loadStyle("https://cdn.datatables.net/1.13.2/css/dataTables.bootstrap5.min.css")); // 确保表格DOM存在且userData已加载后初始化 if (userData) { window.jQuery('#example').DataTable(); } fetchCustomers(); initialUpdate(); console.log(updateSuccess); } catch (err) { console.error("加载资源失败:", err); } }; initDataTable(); // 组件卸载时清理资源 return () => { scripts.forEach(script => document.head.removeChild(script)); styles.forEach(style => document.head.removeChild(style)); // 销毁DataTable实例 if (window.jQuery?.DataTable) { window.jQuery('#example').DataTable().destroy(); } }; }, [userData]); // 补充缺失的事件处理函数 const onClick = (e) => { console.log(e.target.name); }; const onSubmit = (e) => { e.preventDefault(); }; return userData ? ( <div> <button type="button" className="btn btn-primary" name="create" onClick={onClick}> <i className="bi bi-plus-square-fill"></i>Create </button> <form onSubmit={onSubmit}> <table id="example" className="table"> <thead> <tr> <th scope="col">Serial</th> <th scope="col">Customer Name</th> <th scope="col">MAC</th> <th scope="col">Action</th> </tr> </thead> <tbody> {userData.map((customer, index) => ( <tr key={customer.id}> <th scope="row">{index + 1}</th> <td>{customer.customer_name}</td> <td>{customer.customer_mac}</td> <td> <button type="submit" name="cid" value={customer.id} className="btn btn-primary" onClick={onClick} >Modify</button> </td> </tr> ))} </tbody> </table> </form> </div> ) : ( <div>Please login first</div> ) }; export default ViewCustomers;
额外注意点
- 原代码中
onClick和onSubmit函数未定义,需要补充实现,否则点击按钮会报错。 - 使用npm方案时,
userData是异步获取的,需在userData变化的useEffect中初始化DataTables,避免表格空数据时初始化失败。 - 组件卸载时一定要销毁DataTable实例,避免内存泄漏。
内容的提问来源于stack exchange,提问作者xi chen
相关产品推荐
相关产品推荐

