Javascript 反应中的脚本加载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42847126/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:28:05  来源:igfitidea点击:

Script load in react

javascriptreactjsreact-redux

提问by Abhijeet

I want to load the script from a CDN and then execute a function exposed by that script in React:

我想从 CDN 加载脚本,然后在 React 中执行该脚本公开的函数:

componentWillMount() {
    console.log('componentWillMount is called');
    const script = document.createElement('script');
    script.src = 'https://foo.azurewebsites.net/foo.js';
    document.body.appendChild(script);
}


componentDidMount() {
    console.log('componentDidMount is called');
    window.foo.render({
        formId: '77fd8848-791a-4f13-9c82-d24f9290edd7',
    }, '#container');
}


render() {
    console.log('render is called');
    return (
        <div id="container"></div>
    );
}

The script sometimes takes time to load (generally first time) and when componentDidMount()is called "foo" is not available and I get an error like this:

脚本有时需要时间来加载(通常是第一次),何时componentDidMount()调用“foo”不可用,我收到如下错误:

TypeError: Cannot read property 'render' of undefined

类型错误:无法读取未定义的属性“渲染”

How can I assure that componentDidMount()is called once the script is loaded successfully?

如何确保componentDidMount()在成功加载脚本后调用它?

回答by Y.Peng

I don't think it's a good idea to load scripts in componentWillMount() or componentDidMount(), according to React Component Specs and Lifecycle.

根据React Component Specs 和 Lifecycle,我认为在 componentWillMount() 或 componentDidMount() 中加载脚本不是一个好主意。

The code below may help you.

下面的代码可以帮到你。

function new_script(src) {
  return new Promise(function(resolve, reject){
    var script = document.createElement('script');
    script.src = src;
    script.addEventListener('load', function () {
      resolve();
    });
    script.addEventListener('error', function (e) {
      reject(e);
    });
    document.body.appendChild(script);
  })
};
// Promise Interface can ensure load the script only once.
var my_script = new_script('http://example.com/aaa.js');

class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      status: 'start'
    };
  }

  do_load = () => {
    var self = this;
    my_script.then(function() {
      self.setState({'status': 'done'});
    }).catch(function() {
      self.setState({'status': 'error'});
    })
  }

  render() {
    var self = this;
    if (self.state.status === 'start') {
      self.state.status = 'loading';
      setTimeout(function () {
        self.do_load()
      }, 0);
    }

    return (
      <div>{self.state.status}   {self.state.status === 'done' && 'here you can use the script loaded'}</div>
    );
  }
}

回答by Abraham William

Leading decorators must be attached to a class declaration while using the above resolution

使用上述解决方案时,必须将前导装饰器附加到类声明