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

React项目引入jQuery CDN后仍报Uncaught ReferenceError错误求助

解决React中使用DataTable时「Uncaught ReferenceError: jQuery is not defined」的问题

核心问题分析

你的代码存在两个关键问题导致错误:

  1. 重复且冲突的jQuery引入:同时通过import $ from 'jquery'引入npm包版本,又动态加载CDN版本的jQuery。DataTables依赖全局的jQuery变量,但你直接调用的$是模块内的局部变量,且CDN脚本是异步加载的,执行$('#example').DataTable()时全局jQuery可能还未就绪。
  2. 异步脚本加载未处理顺序与完成状态:动态创建的脚本默认异步加载,你直接在脚本添加到DOM后立刻初始化DataTables,此时jQuery或DataTables脚本可能还未加载完成,自然找不到jQuery变量。

解决方案一:使用npm管理依赖(推荐,符合React项目规范)

放弃动态加载CDN的方式,直接通过npm安装所需依赖,避免异步加载问题:

  1. 安装依赖
npm install jquery datatables.net datatables.net-bs5 bootstrap
  1. 修改组件代码
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 16:20:38