从第 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)
}
我基本上是尝试从 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)
}