从第 3 方 JS 文件加载设置 ReactJS 状态

Setting ReactJS state from 3rd party JS file onload

我基本上是尝试从 React 组件的 componentWillMount() 函数中执行此操作 class。

    const script = document.createElement("script");

    script.src = "https://apis.google.com/js/client.js";
    script.async = true;
    script.onload = function() {
      gapi.client.setApiKey(API_KEY);
      gapi.client.load('youtube', 'v3');
      this.setState({ gapiReady: true }); 
      // ^ Doesn't work because `this` refers to the script rather than the component itself.
    };

    document.body.appendChild(script);

为了完整起见,将整个组件粘贴在这里:

import React, { Component } from 'react';
import VideoPlayer from '../../components/VideoPlayer/VideoPlayer';
import VideoInfo from '../../components/VideoInfo/VideoInfo';
import SearchBox from '../../components/SearchBox/SearchBox';
import './App.css';

class App extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = {};
  };

  componentWillMount() {
    const script = document.createElement("script");

    script.src = "https://apis.google.com/js/client.js";
    script.async = true;
    script.onload = function() {
      gapi.client.setApiKey(API_KEY);
      gapi.client.load('youtube', 'v3');
      this.setState({ gapiReady: true }); // Doesn't work because `this` refers to the script rather than the component
    };

    document.body.appendChild(script);
  };

  render() {
    if (this.state.gapiReady) {
      return (
        <div className="wrap">
          <div className="sidebar">
            <SearchBox />
            <VideoInfo videoId="vkRDOcma9Qk" />
          </div>
          <div className="content">
            <VideoPlayer />
          </div>
        </div>
      );
    } else {
      return (
        <div>Loading...</div>
      )
    }
  };
}

export default App;

我的目标是仅在脚本完全加载后在 render() 函数中呈现 VideoInfo 和 VideoPlayer 组件,否则此组件上的代码将失败,因为它们依赖于已加载的脚本。

我是不是做错了?

首先,你应该做这样的事情 componentDidMount 这样代码仍然可以 运行 即使在它无法访问 document 对象的情况下.如果您不进行服务器端渲染,这并不重要,但这是 React 中的常见模式。

要解决 this 的问题,您可以使用箭头函数来定义 script.onload。使用箭头函数定义的函数不会创建新的上下文,因此 this 与函数定义的范围保持相同。

TLDR 将您的 componentWillMount 方法替换为:

componentDidMount () {
  const script = document.createElement("script")

  script.src = "https://apis.google.com/js/client.js"
  script.async = true

  script.onload = () => {
    gapi.client.setApiKey(API_KEY)
    gapi.client.load('youtube', 'v3')
    this.setState({ gapiReady: true })
  }

  document.body.appendChild(script)
}