如何在React组件中动态加载js脚本

网上找了很多方案,比如react-helmet等各种包,都不行。

从原理上,他们都是类似如下的原生方案:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
const script = document.createElement("script"); script.src = url; document.head.appendChild(script);
const script = document.createElement("script");
script.src = url;
document.head.appendChild(script);

这种方案是存在问题的,script是异步加载的,不等加载完毕直接往下执行,是找不到对象的。

这里给出最终解法:在onload回调中再渲染。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 ;
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 ;
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 ;
  1. 上面使用了FC方式组件。
  2. 这里用useEffect来模拟了mount和unmount。
  3. 注意在unmount中要卸载动态加载的脚本。
  4. 在把所有script注册onload事件到onDynamicJSLoad回调上,在这里根据计数器来判断是否加载完了所有的脚本。

 

Leave a Reply

Your email address will not be published. Required fields are marked *