在 Web 应用开发中,动态加载外部脚本是一个常见需求,特别是在需要集成第三方库或服务时。然而,在 React 应用中管理脚本加载可能会变得复杂。useScript
钩子提供了一种优雅的方式来处理外部脚本的加载、错误处理和清理,使得在 React 组件中动态加载脚本变得简单和可靠。以下是如何实现和使用这个自定义钩子:
const useScript = src => {const [status, setStatus] = React.useState(src ? 'loading' : 'idle');React.useEffect(() => {if (!src) {setStatus('idle');return;}let script = document.querySelector(`script[src="${src}"]`);if (!script) {script = document.createElement('script');script.src = src;script.async = true;script.setAttribute('data-status', 'loading');document.body.appendChild(script);const setDataStatus = event => {script.setAttribute('data-status',event.type === 'load' ? 'ready' : 'error');};script.addEventListener('load', setDataStatus);script.addEventListener('error', setDataStatus);} else {setStatus(script.getAttribute('data-status'));}const setStateStatus = event => {setStatus(event.type === 'load' ? 'ready' : 'error');};script.addEventListener('load', setStateStatus);script.addEventListener('error', setStateStatus);return () => {if (script) {script.removeEventListener('load', setStateStatus);script.removeEventListener('error', setStateStatus);}};}, [src]);return status;
};const script ='data:text/plain;charset=utf-8;base64,KGZ1bmN0aW9uKCl7IGNvbnNvbGUubG9nKCdIZWxsbycpIH0pKCk7';const Child = () => {const status = useScript(script);return <p>Child status: {status}</p>;
};const MyApp = () => {const status = useScript(script);return (<><p>Parent status: {status}</p><Child /></>);
};ReactDOM.createRoot(document.getElementById('root')).render(<MyApp />
);
这个技巧的关键点包括:
使用
useState
来跟踪脚本的加载状态。使用
useEffect
来处理脚本的加载、错误处理和清理逻辑。检查是否已存在相同 src 的脚本元素,避免重复加载。
使用
data-status
属性来跟踪脚本的加载状态。添加事件监听器来处理加载成功和失败的情况。
使用这个钩子时,需要注意以下几点: