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

网上找了很多方案,比如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 ;
  1. 上面使用了FC方式组件。
  2. 这里用useEffect来模拟了mount和unmount。
  3. 注意在unmount中要卸载动态加载的脚本。
  4. 在把所有script注册onload事件到onDynamicJSLoad回调上,在这里根据计数器来判断是否加载完了所有的脚本。

 

Leave a Reply

Your email address will not be published.