反应-重新渲染

时间:2020-03-04 13:25:00

标签: javascript reactjs rendering spotify

我是第一次使用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>
    )
  }

任何帮助都会很棒:)

2 个答案:

答案 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