React 17使用原生JS版TypeIt插件报未定义错误如何解决
问题解决方法
根因分析
报错核心原因为当前自定义
useScriptHook没有返回脚本加载状态,组件内的TypeIt初始化逻辑执行时,外部脚本还未加载完成,全局作用域未挂载TypeIt对象,固定100ms延迟的策略不可靠,受网络/设备性能影响很大。
第一步:改造useScript Hook,新增加载状态返回
修改后的Hook会监听脚本加载完成、加载失败事件,向外返回对应状态供上层组件使用:
import { useEffect, useState } from 'react'; const useScript = resourceUrl => { // 存储脚本加载状态 const [state, setState] = useState({ loaded: false, error: false }); useEffect(() => { const script = document.createElement('script'); script.src = resourceUrl; script.async = true; const onScriptLoad = () => { setState({ loaded: true, error: false }); }; const onScriptError = () => { setState({ loaded: false, error: true }); }; script.addEventListener('load', onScriptLoad); script.addEventListener('error', onScriptError); document.body.appendChild(script); return () => { script.removeEventListener('load', onScriptLoad); script.removeEventListener('error', onScriptError); document.body.removeChild(script); }; }, [resourceUrl]); return state; }; export default useScript;
第二步:改造TypeText组件,等脚本加载完成后再初始化
调整组件逻辑,只有脚本加载完成、且全局存在TypeIt对象时再执行初始化,同时补充实例销毁逻辑避免内存泄漏:
import React, { useEffect, useRef } from 'react' import useScript from '../../Hooks/useScript' const TypeText = () => { // 接收脚本加载状态 const { loaded, error } = useScript('vendor/typeTextScript.js') const typeTrigger = useRef() // 存储TypeIt实例,用于卸载时销毁 const typeItInstance = useRef(null) useEffect(()=> { // 只有脚本加载完成、DOM节点存在、全局有TypeIt时才执行初始化 if (loaded && typeTrigger.current && window.TypeIt) { typeItInstance.current = new window.TypeIt(typeTrigger.current, { strings: "This is my string!", speed: 75, loop: true, }).go(); } return () => { // 组件卸载时销毁实例 if (typeItInstance.current) { typeItInstance.current.destroy() } } // 依赖项新增loaded状态,脚本加载完成后自动触发初始化 }, [loaded]) // 可选:加载失败时的兜底展示 if (error) return <p>打字效果加载失败</p> return ( <> <h1>This is a TypeText component</h1> <p ref={typeTrigger}></p> </> ) } export default TypeText
额外注意事项
- 请确认你本地的
vendor/typeTextScript.js是TypeIt的UMD格式版本,只有UMD格式的包才会自动挂载TypeIt到全局window对象上,如果你用的是ESModule格式的本地文件,不会挂载全局对象,会持续出现未定义报错。 - 如果你不需要本地存储脚本,直接启用你注释的CDN地址即可,该地址为UMD格式,可正常使用。
内容的提问来源于stack exchange,提问作者Rejin Jose
相关产品推荐
相关产品推荐

