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模块,可直接导入:
这种方式由Webpack自动处理打包,无需手动创建script标签。import './polyfill.js';
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
相关产品推荐
相关产品推荐

