我是第一次使用react构建一个简单的Spotify应用。当前,我能够渲染用户正在播放的当前曲目,并且该曲目会自动出现在页面上。如果我快速更改曲目(几秒钟之内),它将在页面上呈现新的曲目详细信息。但是,如果我等待几秒钟,它将停止渲染。有什么原因吗?
下面是我的代码示例
return (
<div className="App">
<a href='http://localhost:8888'>
<button>Login But With Spotify</button>
</a>
{this.getNowPlaying()}
<div> Now Playing: { this.state.nowPlaying.name} </div>
<div> By: { this.state.nowPlaying.artist} </div>
<div> Id: { this.state.nowPlaying.id} </div>
<div>
<img src={ this.state.nowPlaying.image} style={{ width: 100}}/>
</div>
</div>
)
}
任何帮助都会很棒:)
答案 0 :(得分:0)
这是因为您在render方法中调用了API调用方法“ getNowPlaying”。
react的每个渲染周期都会调用render方法,因此它可能被调用多次。
从渲染中删除{this.getNowPlaying()}
,并创建一个方法“ componentDidMount”并将其放置在此处。 (请参见下面的代码)
“ componentDidMount”方法是组件成功安装(初始化)后调用的React组件生命周期方法。
在react's class component lifecycle methods docs中阅读更多内容
import React, { Component } from 'react';
import './App.css';
import Spotify from 'spotify-web-api-js';
const spotifyWebApi = new Spotify();
class App extends Component {
constructor(){
super();
const params = this.getHashParams();
this.state ={
loggedIn: params.access_token ? true : false,
nowPlaying: {
name: 'Not Checked',
image: ''
}
}
if (params.access_token){
spotifyWebApi.setAccessToken(params.access_token)
}
}
componentDidMount() {
this.getNowPlaying()
}
getHashParams() {
var hashParams = {};
var e, r = /([^&;=]+)=?([^&;]*)/g,
q = window.location.hash.substring(1);
while ( e = r.exec(q)) {
hashParams[e[1]] = decodeURIComponent(e[2]);
}
return hashParams;
}
getNowPlaying(){
spotifyWebApi.getMyCurrentPlaybackState()
.then((response) => {
this.setState({
nowPlaying: {
name: response.item.name,
image: response.item.album.images[1].url,
artist: response.item.artists[0].name,
id: response.item.id
}
})
}
)
}
render() {
return (
<div className="App">
<a href='http://localhost:8888'>
<button>Login But With Spotify</button>
</a>
<div> Now Playing: { this.state.nowPlaying.name} </div>
<div> By: { this.state.nowPlaying.artist} </div>
<div> Id: { this.state.nowPlaying.id} </div>
<div>
<img src={ this.state.nowPlaying.image} style={{ width: 100}}/>
</div>
</div>
)
}
}
答案 1 :(得分:0)
好的,这是一些基本的东西。
基本上,在您的代码中,每次重新渲染时都会得到新内容。这是一个问题,仅在状态,父项或道具(并非总是)变化时才发生重新渲染。这可能会导致一些问题。
您看到它起作用,因为您在触发This.setState
之前更改了歌曲,因此在设置状态时,它将触发组件重新渲染,从而再次调用该函数。此时,如果响应已更改(基本上是更改歌曲),则状态会更新并重复此步骤;否则,如果响应相同(同时未更改歌曲),则状态不变(导致组件不重新呈现->不重新获取数据);
在这里您可以找到解决方案。一个是类组件,一个是钩子(我只测试了钩子的一个)。我个人会推荐第二个,因为它更少的代码,更灵活且更易于理解!
希望我能为您服务!
类组件
import React, { Component } from 'react';
import './App.css';
import Spotify from 'spotify-web-api-js';
const spotifyWebApi = new Spotify();
class App extends Component {
constructor(){
super();
const params = this.getHashParams();
this.state ={
loggedIn: params.access_token ? true : false,
nowPlaying: {
name: 'Not Checked',
image: ''
}
}
if (params.access_token){
spotifyWebApi.setAccessToken(params.access_token)
}
}
getHashParams() {
var hashParams = {};
var e, r = /([^&;=]+)=?([^&;]*)/g,
q = window.location.hash.substring(1);
while ( e = r.exec(q)) {
hashParams[e[1]] = decodeURIComponent(e[2]);
}
return hashParams;
}
componentDidMount(){
this.getNowPlaying();
}
getNowPlaying(){
spotifyWebApi.getMyCurrentPlaybackState()
.then((response) => {
this.setState({
nowPlaying: {
name: response.item.name,
image: response.item.album.images[1].url,
artist: response.item.artists[0].name,
id: response.item.id
}
})
this.getNowPlaying();
}
)
}
render() {
return (
<div className="App">
<a href='http://localhost:8888'>
<button>Login But With Spotify</button>
</a>
<div> Now Playing: { this.state.nowPlaying.name} </div>
<div> By: { this.state.nowPlaying.artist} </div>
<div> Id: { this.state.nowPlaying.id} </div>
<div>
<img src={ this.state.nowPlaying.image} style={{ width: 100}}/>
</div>
</div>
)
}
}
挂钩
import React, { useState, useEffect, useCallback } from "react";
import "./App.css";
import Spotify from "spotify-web-api-js";
const spotifyWebApi = new Spotify();
function App() {
//not used?
const [loggedIn, setLoggedIn] = useState();
//telling whether the component is mount or not
const [isComponentMount,setIsComponentMount]=useState(true);
//response container
const [nowPlaying, setNowPlaying] = useState({
name: "Not Checked",
image: "",
artist: "",
id: ""
});
//Fetches the newest data
const getNowPlaying = useCallback(() => {
//Needed to stop the infinite loop after the component gets closed
if(!isComponentMount)return;
spotifyWebApi.getMyCurrentPlaybackState().then(response => {
setNowPlaying({
name: response.item.name,
image: response.item.album.images[1].url,
artist: response.item.artists[0].name,
id: response.item.id
});
//Change this one as you like (perhaps a timeout?)
getNowPlaying();
});
}, []);
useEffect(() => {
//Get hash params
const params = {};
var e,
r = /([^&;=]+)=?([^&;]*)/g,
q = window.location.hash.substring(1);
while ((e = r.exec(q))) {
params[e[1]] = decodeURIComponent(e[2]);
}
if (params.access_token) {
spotifyWebApi.setAccessToken(params.access_token);
}
getNowPlaying();
return ()=>{
setIsComponentMount(false);
}
}, [getNowPlaying]);
return (
<div className="App">
<a href="http://localhost:8888">
<button>Login But With Spotify</button>
</a>
<div> Now Playing: {nowPlaying.name} </div>
<div> By: {nowPlaying.artist} </div>
<div> Id: {nowPlaying.id} </div>
<div>
<img src={nowPlaying.image} style={{ width: 100 }} alt="" />
</div>
</div>
);
}
export default App