只能更新已安装或正在安装的组件。由于路由器
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 的某些最佳方面背道而驰。
我想用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 的某些最佳方面背道而驰。