nextjs Script 组件的常见问题

有哪些问题

1. 如果脚本的执行有依赖关系

可能等待执行的脚本先于其所依赖的脚本加载完成并执行,导致错误的产生。

这种情形出现的原因在于这些脚本是后面通过 Script 动态加载的,而非刚开始就写入了 HTML 中。所以根据浏览器渲染的原理,script 加载的时间是动态的,需要控制代码来确保。

2. 如果某段 src 引入的代码加载过,那么就不会重新加载了,不会触发加载完成回调

简言之,若先后引入了同样的 src, 那么后加载的代码不会再加载一遍,并且不会触发 onLoad 回调。

而且,如果是通过 children 写入 Script, 而非通过 src 属性,这个时候没法判断两段脚本是否需要利用缓存,有可能会执行两边逻辑。所以需要通过 id 字段来区分,以避免上述情况。

为什么会出现上述情况

什么时候会出现上面的这些问题,和应用 Script 组件的场景有关系。

在 nextjs 应用中,当依赖的某个 sdk, 又需要依赖另外的下层 sdk 时就有可能出现上面的问题。比如当动态加载某个 sdk, 但是这个 sdk 需要依赖 react,而 react 也是动态加载的,就有可能出现执行顺序不一定的问题。

还有比如某个子组件中引用了 react lib, 但是不能保证系统的其他地方没有提前引入该同样 src 的 react lib,那么可能就会出现后面动态加载该 lib 的子组件无法触发 onLoad 回调,这个时候需要设置的是 onReady 属性。而且这个 onReady 属性不能在 render 的时候生成,而应该提前算好,否则会引发 render 死循环。

示例组件

下面演示 nextjs ScriptsLoader 组件的代码

import React from 'react';
import Script from 'next/script';

class ScriptsLoader extends React.Component {
  constructor(props) {
    super(props);
    let { scripts } = props;
    this.scriptsLoad = scripts.map(() => false);
    this.handleScriptsReady = scripts.map((src, i) => {
      return () => this.handleReady(i);
    });
  }

  handleReady(i) {
    this.scriptsLoad[i] = true;
    if (this.isLoadOk()) {
      this.forceUpdate();
    }
  }

  isLoadOk() {
    return this.scriptsLoad.every(Boolean);
  }

  render() {
    let loadOk = this.isLoadOk();
    // console.log('[render:loadOk](%s)', loadOk);
    let { scripts, children } = this.props;
    return (
      <React.Fragment>
        {scripts.map((src, i) => (
          <Script
            key={i}
            data-idx={i}
            src={src}
            onReady={this.handleScriptsReady[i]}
          />
        ))}

        {loadOk && children}
      </React.Fragment>
    );
  }
}

ScriptsLoader.defaultProps = {
  scripts: [],
};

关于 nextjs Script 组件还有哪些常见问题需要注意,欢迎补充,在下方评论区留言。

关于本文如您有任何想法和意见,欢迎与我们联系,邮箱地址zhi@uqugu.com
您对本文有什么看法,喜欢或者不喜欢都可以发表意见。