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

React中动态加载本地脚本失败,远程链接正常求解决

React本地动态加载脚本失败排查与解决

问题描述

使用远程链接加载脚本可正常运行:

const createScript = () => {
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = 'https://bernardo-castilho.github.io/DragDropTouch/DragDropTouch.js';
  script.onload = function () {
    setScriptLoadingState('LOADED');
    console.log('Script loaded');
  };
  script.onerror = function () {
    setScriptLoadingState('FAILED');
  };
  document.body.appendChild(script);
};

但将脚本下载到本地后,改用相对路径./polyfill.js加载失败:

const createScript = () => {
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = './polyfill.js';
  script.onload = function () {
    setScriptLoadingState('LOADED');
    console.log('Script loaded');
  };
  script.onerror = function () {
    setScriptLoadingState('FAILED');
  };
  document.body.appendChild(script);
};

完整代码如下:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
  Scheduler,
  WeekView,
  MonthView,
} from '@progress/kendo-react-scheduler';

import { Grid, GridColumn } from '@progress/kendo-react-grid';

import gridData from './data.js';

const App = () => {
  const MyScheduler = React.createRef();
  const [data, setData] = React.useState([]);
  const [dragItem, setDragItem] = React.useState('');
  const [width, setWidth] = React.useState(window.innerWidth);
  const [scriptLoadingState, setScriptLoadingState] = React.useState('IDLE');

  const createScript = () => {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = './polyfill.js';
    script.onload = function () {
      setScriptLoadingState('LOADED');
      console.log('Script loaded');
    };
    script.onerror = function () {
      setScriptLoadingState('FAILED');
    };
    document.body.appendChild(script);
  };

  const handleDropItem = (e) => {
    let start = e.target.getAttribute('data-slot-start');
    let end = e.target.getAttribute('data-slot-end');
    let startDate = new Date(parseInt(start));
    let endDate = new Date(parseInt(end));
    let newEvent = {
      id: dragItem.taskID,
      title: dragItem.title,
      StartTimezone: null,
      start: startDate,
      end: endDate,
    };
    setData([newEvent, ...data]);
  };
  React.useEffect(() => {
    createScript();

    window.addEventListener('resize', handleWindowSizeChange);
    let schedulerElement = MyScheduler.current.element;
    schedulerElement.addEventListener('drop', handleDropItem);
    schedulerElement.addEventListener('dragover', (e) => e.preventDefault());

  });

  const GridRowRender = (tr, props) => {
    const trProps = {
      draggable: true,
      onDragStart: (e) => {
        setDragItem(props.dataItem);
      },
    };
    return React.cloneElement(tr, { ...trProps }, tr.props.children);
  };
  return (
    <>
      <Scheduler
        data={data}
        defaultDate={new Date('2013/6/13')}
        ref={MyScheduler}
      >
        <WeekView showWorkHours={false} />
        <MonthView />
      </Scheduler>
      <hr />
      <Grid data={gridData} rowRender={GridRowRender}>
        <GridColumn field="taskID" />
        <GridColumn field="title" />
      </Grid>
    </>
  );
};

ReactDOM.render(<App />, document.querySelector('my-app'));

问题原因与解决方法

1. 文件路径错误

  • 相对路径./polyfill.js是相对于当前页面的URL,而非组件文件位置。若使用Create React App等脚手架,页面根URL为/,需将脚本放在public文件夹下,路径改为/polyfill.js。
  • 操作步骤:将polyfill.js移入项目根目录的public文件夹,修改代码中script.src = '/polyfill.js';。

2. 静态资源未被正确打包

  • 若项目使用Webpack等打包工具,组件目录下的脚本不会自动复制到输出目录。除了放入public目录,若脚本支持ES模块,可直接导入:
    import './polyfill.js';
    
    这种方式由Webpack自动处理打包,无需手动创建script标签。

3. 路径适配子部署环境

  • 若项目部署在子路径下,相对路径可能失效。使用process.env.PUBLIC_URL(Create React App内置变量)拼接路径更可靠:
    script.src = `${process.env.PUBLIC_URL}/polyfill.js`;
    

4. 修复重复加载与内存泄漏

  • 当前useEffect无依赖数组,会在组件每次渲染时调用createScript,导致重复创建script标签。添加空依赖数组[],确保仅在组件挂载时加载一次,同时补充清理逻辑:
    // 先补充handleWindowSizeChange函数
    const handleWindowSizeChange = () => {
      setWidth(window.innerWidth);
    };
    
    React.useEffect(() => {
      createScript();
    
      window.addEventListener('resize', handleWindowSizeChange);
      const schedulerElement = MyScheduler.current.element;
      schedulerElement.addEventListener('drop', handleDropItem);
      const dragOverHandler = (e) => e.preventDefault();
      schedulerElement.addEventListener('dragover', dragOverHandler);
    
      // 组件卸载时清理事件监听
      return () => {
        window.removeEventListener('resize', handleWindowSizeChange);
        schedulerElement.removeEventListener('drop', handleDropItem);
        schedulerElement.removeEventListener('dragover', dragOverHandler);
      };
    }, []);
    

5. 利用浏览器工具定位问题

  • 打开浏览器开发者工具(F12),查看Network标签的请求状态,确认脚本是否返回404错误,验证路径是否正确。
  • 查看Console标签的报错信息,定位脚本语法错误、依赖缺失等问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 17:45:37