只能更新已安装或正在安装的组件。由于路由器

Can only update a mounted or mounting component. due to Router

我想用react.js写一个音乐播放器。初始化后播放器运行良好。

但是一旦我将带有路由器的站点更改为音乐列表,控制台就会显示错误:

Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the Player component

我已经在代码中标记了这一行。

我想,当我更改站点时,播放器组件可能会被卸载。但是没有 componentWillUnmount 函数,没有什么不同。

Here是我的项目。

提前致谢!

player.js

import React, {Component} from 'react';
import '../../styles/player.less';
import Progress from '../commen/progress.js';
import {Link} from 'react-router-dom';

let duration = null;

export default class Player extends Component {

    constructor(props){
        super(props);

        this.state={
            progress: 0,
            volume: 0,
            isPlay: true,
        },

        this.play=this.play.bind(this);
        this.progressChangeHandler=this.progressChangeHandler.bind(this);
        this.volumeChangeHandler=this.volumeChangeHandler.bind(this);
    }

    componentDidMount(){

        $('#player').bind($.jPlayer.event.timeupdate,(e)=>{
            duration = e.jPlayer.status.duration;//total duration of the song
            this.setState({//here is the problem !!!!!!!!!!!!!!!!!!!!!!!
                volume: e.jPlayer.options.volume*100,
                progress:e.jPlayer.status.currentPercentAbsolute
            });//how lange already played
        });
    }

    componentWillUnMount(){
        //$('#player').unbind($.jPlayer.event.timeupdate);
    }

    //从子组件中获得值
    //change progress
    progressChangeHandler(progress){

            $('#player').jPlayer('play', duration * progress); 

    }
    //change volume
    volumeChangeHandler(progress){
        $('#player').jPlayer('volume', progress);
    }

    //play pause switcher
    play(){
        if(this.state.isPlay){
            $('#player').jPlayer('pause');
        }else{
            $('#player').jPlayer('play');
        }

        this.setState({
            isPlay: !this.state.isPlay,
        })
    }

    render(){
        return(
            <div className="player-page">
                <h1 className="caption">
                    <Link to="/list">My Favorite Music</Link>
                </h1>
                <div className="mt20 row">
                    <div className = "controll-wrapper">
                        <h2 className="music-title">{this.props.currentMusicItem.title}</h2>
                        <h3 className="music-artist mt10">{this.props.currentMusicItem.artist}</h3>
                        <div className="row mt20">
                            <div className="left-time -col-auto">-2:00</div>
                            <div className="volume-container">
                                <i className="icon-volume rt"></i>
                                <div className="volume-wrapper">
                                    <Progress 
                                        progress={this.state.volume} 
                                        onProgressChange={this.volumeChangeHandler}
                                        barColor="#aaa"></Progress>
                                </div>
                            </div>
                        </div>
                        <div className="progress-container">
                            <Progress 
                                progress={this.state.progress}
                                onProgressChange={this.progressChangeHandler}>
                            </Progress>
                        </div>
                        <div className="mt35 row">
                            <div>
                                <i className="icon prev"></i>
                                <i className={`icon ml20 ${this.state.isPlay ? 'pause' : 'play'}`} onClick={this.play}></i>
                                <i className="icon next ml20"></i>
                            </div>
                            <div className="-col-auto">
                                <i className="icon repeat-cycle"></i>
                            </div>
                        </div>
                    </div>
                    <div className="-col-auto cover">
                        <img src={this.props.currentMusicItem.cover} alt={this.props.currentMusicItem.title}/>
                    </div>
                </div>
            </div>


            /**<div className="player-page">
                <Progress progress={this.state.progress} onProgressChange={this.progressChangeHandler}></Progress>
            </div>**/
        )
    }
}

root.js

import React, {Component} from 'react';
import Header from './commen/header.js';
import Player from './page/player.js';
import {MUSIC_LIST} from '../config/musiclist';
import MusicListUI from './page/musiclistui.js';

import {BrowserRouter as Router, Switch, Route, Link} from 'react-router-dom';


export default class Root extends Component{
    constructor(props){
        super(props);
        this.state={
            musiclist: MUSIC_LIST,
            currentMusicItem: MUSIC_LIST[0]
        }
    }

    componentDidMount(){


        $('#player').jPlayer({
            ready:function(){
                $(this).jPlayer('setMedia',{
                    mp3:'http://oj4t8z2d5.bkt.clouddn.com/%E9%AD%94%E9%AC%BC%E4%B8%AD%E7%9A%84%E5%A4%A9%E4%BD%BF.mp3'
                }).jPlayer('play');
            },
            supplied:'mp3',
            wmode: 'window'
        });


    }


    render(){

        const Home=() => (
            <Player
                currentMusicItem={this.state.currentMusicItem}
            />
        );

        const List = () => (
            <MusicListUI
                currentMusicItem={this.state.currentMusicItem}
                musiclist={this.state.musiclist}
            />
        );

        return(
            <Router>
                <div>
                    <Header/>
                    <Switch>
                        <Route exact path="/" component={Home}/>
                        <Route path="/list" component={List}/>
                    </Switch>
                </div>
            </Router>   
        )
    }
}

错误总结得很好。当您更改路由时,组件将被卸载,并且回调会尝试 setState 卸载组件。在这种情况发生之前,您必须弄清楚如何进行清理。我看到你已经知道可以使用 componentWillUnmount,但是你打错了:

componentWillUnMount(){  // should be componentWillUnmount!
    //$('#player').unbind($.jPlayer.event.timeupdate);
}

另请注意,bind 方法已被弃用。

路由器不是你的问题。您的问题是您正在与 React 的基本设计范式作斗争……或者可能是常识。您不应该尝试对当前不存在的组件执行操作。那会完成什么?在你的例子中,你有一堆你没有删除的事件监听器。

附带说明一下,您使用的 jQuery 数量惊人。您应该尽可能多地使用 this.setState。您的编程风格与 React 的某些最佳方面背道而驰。