网上找了很多方案,比如react-helmet等各种包,都不行。
从原理上,他们都是类似如下的原生方案:
const script = document.createElement("script"); script.src = url; document.head.appendChild(script);
这种方案是存在问题的,script是异步加载的,不等加载完毕直接往下执行,是找不到对象的。
这里给出最终解法:在onload回调中再渲染。
interface Prop { } const XXXComponent : React.FC<Prop> = (prop) => { // ondynamicload let dynamicJsCnt = 0 let onDynamicJSLoad = () => { console.log(dynamicJsCnt) if (--dynamicJsCnt == 0) { ...渲染逻辑 } } // mount / unmount useEffect(() => { let dynamicLoads: HTMLElement[] = [] const cssList = [ 'https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css', .... ] cssList.forEach((u) => { const style = document.createElement("link"); style.href = u; style.rel = 'stylesheet'; dynamicLoads.push(style) document.head.appendChild(style); }) const jsList = [ 'https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js', ... ] dynamicJsCnt = jsList.length; jsList.forEach((u) => { const script = document.createElement("script"); script.src = u; script.addEventListener('load', onDynamicJSLoad) dynamicLoads.push(script) document.head.appendChild(script); }) // unmount return () => { dynamicLoads.forEach(e => console.log(document.head.removeChild(e))) } }, []) // render return ( <div> ... </div> ) }; export default XXXComponent ;
- 上面使用了FC方式组件。
- 这里用useEffect来模拟了mount和unmount。
- 注意在unmount中要卸载动态加载的脚本。
- 在把所有script注册onload事件到onDynamicJSLoad回调上,在这里根据计数器来判断是否加载完了所有的脚本。