【问题标题】:React - Re renderReact - 重新渲染
【发布时间】:2020-03-04 13:25:00
【问题描述】:

我第一次使用 react 构建了一个简单的 spotify 应用程序。 Currenty 我能够呈现用户正在播放的当前曲目,它会自动出现在页面上。如果我快速更改曲目(在几秒钟内),它会将新的曲目详细信息呈现到页面上。但是,如果我等待几秒钟,它会停止渲染。有什么原因吗?

下面是我的代码示例

    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>
    )
  }

任何帮助都会很棒:)

【问题讨论】:

  • 请贴出更多代码,整个课程都很棒!
  • 我在下面发布了整个课程 - OP

标签: javascript reactjs rendering spotify


【解决方案1】:

这是因为你在 render 方法中调用了 API 调用方法“getNowPlaying”。

react的每个render周期都会调用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>
    )
  }
}

【讨论】:

  • 嘿,我尝试过使用上面提到的 componentDidMount() 函数,但是当我在 spotify 中切换到新轨道时,它现在根本没有改变..
  • 在这种情况下,您应该寻找反应式 API、websocket 或其他能够让您注册侦听器以发现跟踪更改的东西......或者您需要实施民意调查以定期更新它,比如“this.interval = setInterval(() => this.getNowPlaying(), 5000)”(你需要实现 componentWillUnmount 来清除该间隔以防止内存泄漏)
【解决方案2】:

好的,这是一些基本的东西。

基本上,在您的代码中,每次重新渲染都会获得新内容。这里有一个问题,重新渲染仅在状态、父级或(不总是)道具发生变化时发生。这可能会导致一些问题。

你看到它起作用了,因为你在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

【讨论】:

    猜你喜欢
    • 2021-12-29
    • 1970-01-01
    • 2016-12-30
    • 2021-06-03
    • 2020-08-31
    • 2021-12-27
    • 2021-06-19
    • 2018-04-22
    • 2016-05-09
    相关资源
    最近更新 更多