私は今2-3週間反応を学習してきました。私はJavaScriptで数年の経験があります。React Routerを使用しているときに、ネストされたコンポーネントにメソッドと状態を渡すにはどうすればよいですか?
私は、アプリケーションのアーキテクチャがReactコンポーネントを使ってどのように動作するかに慣れるために、Reactでmp3プレーヤーを作っています。 私はいくつかの単純なコンポーネントでmp3を動作させることに成功しました。
私はアプリケーションを拡張することに決めました。私はいくつかのWebページを開発したいと思います。 私はReact Routerをどのように使用して異なる "ページ"にナビゲートするかを学び始めました。 しかし、ルーティング時に、親コンポーネントから子コンポーネントに状態とメソッドを渡すときに問題が発生しました。
アプリケーションコンポーネントには、Header、AudioPlayer、およびControlsコンポーネントが含まれています。これらのコンポーネントはアプリケーションのすべてのページの一部になるためです。 (注:コントロールコンポーネントは、「戻る」、「進む」、「再生」および「一時停止」ボタンとタイマーバーで構成され、現在のオーディオの進行状況を表示します)
ルートのパスが「曲」の場合、 「サウンド」コンポーネントを表示します。 Soundsコンポーネントは、アプリケーションコンポーネントで定義されたselectSoundメソッドとcurrentSoundIndex状態を取る必要があります。 これを達成する方法はありますか?
私はまた、リアクションのベストプラクティスに従っていきたいと思っています。このアプリケーションを構成するためのより良い方法があれば、知りたいと思います。 (例:Reduxを使用すべきですか?) 助けてくれてありがとう。
var{Router,
Route,
IndexRoute,
IndexLink,
hashHistory,
Link } = ReactRouter;
var soundsData = [];
var allSounds = [{"title" : "Egyptian Beat", "artist" : "Sarah Monks", "length": 16, "mp3" : "sounds/0010_beat_egyptian.mp3"},
{"title" : "Euphoric Beat", "artist" : "Sarah Monks", "length": 31, "mp3" : "sounds/0011_beat_euphoric.mp3"},
{"title" : "Latin Beat", "artist" : "Sarah Monks", "length": 59, "mp3" : "sounds/0014_beat_latin.mp3"},
{"title" : "Pop Beat", "artist" : "Sarah Monks", "length": 24, "mp3" : "sounds/0015_beat_pop.mp3"},
{"title" : "Falling Cute", "artist" : "Sarah Monks", "length": 3, "mp3" : "sounds/0027_falling_cute.mp3"},
{"title" : "Feather", "artist" : "Sarah Monks", "length": 6, "mp3" : "sounds/0028_feather.mp3"},
{"title" : "Lose Cute", "artist" : "Sarah Monks", "length": 3, "mp3" : "sounds/0036_lose_cute.mp3"},
{"title" : "Pium", "artist" : "Sarah Monks", "length": 3, "mp3" : "sounds/0039_pium.mp3"}];
var favorites = [];
soundsData[0] = allSounds;
soundsData[1] = favorites;
console.log(soundsData[0][0].title);
var Header = function(props) {
//this is a stateless component and is a child component of the application component.
//it consists of the header navbar of the application
return (<header>
<ul className="header-nav" >
<li className="header-menu-item">
<IndexLink to="/" className="header-menu-link" activeClassName="active">Home</IndexLink>
</li>
<li className="header-menu-item">
<Link to="/songs" className="header-menu-link" activeClassName="active">Songs</Link>
</li>
<li className="header-menu-item navicon" onClick={props.toggleSidePanel} >
<span className="header-menu-link">
<i className="fa fa-navicon"></i>
</span>
</li>
</ul>
</header>
);
}
var Application = React.createClass({
//This class is the main component of the application.
//it takes in the array of soundsData as a property.
getInitialState: function() {
return {
sidePanelIsOpen: false,
currentSoundIndex: 0,
isPlaying: false,
playerDuration: 0,
currentTime: "0:00",
currentWidthOfTimerBar: 0,
backButtonIsDisabled: false,
forwardButtonIsDisabled: false,
playButtonIsDisabled: false
}
},
toggleSidePanel: function(){
var sidePanelIsOpen = this.state.sidePanelIsOpen;
this.setState({sidePanelIsOpen: !sidePanelIsOpen});
},
componentDidMount: function() {
this.player = document.getElementById('audio_player');
},
loadPlayer: function(){
this.player.load();
},
playSound: function(){
clearInterval(this.currentWidthInterval);
this.setState({isPlaying: true});
this.player.play();
var sounds = this.props.route.sounds[0];
var currentIndex = this.state.currentSoundIndex;
var duration = sounds[currentIndex].length; //this.player.duration;
//calculate what the width of the timer bar will be per second.
//98% is the total with of the timer bar
//we will change the width of the timer bar with CSS while the sound is playing. see the TimerBar component.
var widthPerSecond = 98/duration;
//need to store "this" into a variable as it will otherwise be out of scope in the setInterval method
var self = this;
this.currentWidthInterval = setInterval(function(){self.updateTimer(widthPerSecond); console.log('self ' + self.state.currentWidthOfTimerBar); console.log('self load time ' + self.player.currentTime); console.log("duration " + duration);}, 100);
},
pauseSound: function(){
this.setState({isPlaying: false});
this.player.pause();
clearInterval(this.currentWidthInterval);
},
stopPlayer: function() {
this.player.pause();
this.player.currentTime = 0;
this.setState({currentWidthOfTimerBar: 0});
this.setState({currentTime: secondsToMins(this.player.currentTime)});
clearInterval(this.currentWidthInterval);
},
playPauseSound: function(){
//this function is called when the play/pause toggle button is pressed.
if(this.state.isPlaying){
//if the player is in a state of "isPlaying" then we call the pauseSound() method
this.pauseSound();
}else{
//if the player is currently paused (ie the state of "isPlaying" is false) then we call the playSound() method
this.playSound();
}
},
updateTimer: function (widthPerSecond){
//Whenever the playSound() method is called, this method will run every 100 milliseconds.
//it will update the timer bar so we can see the progress on the current sound.
//it will also check to see if the current sound has reached the end of the duration so we can navigate to the next one.
//get the current time of the current sound that is playing
var currentTime = this.player.currentTime;
//calculate the current width of the timer bar so that we can update the CSS width.
var currentWidthOfTimerBar = currentTime*widthPerSecond;
//console.log('this.player.duration ' + this.player.duration);
this.setState({currentWidthOfTimerBar: currentWidthOfTimerBar});
this.setState({currentTime: secondsToMins(currentTime)});
//method cut short here for stackoverflow question
},
selectSound: function(i){
//if user selects a sound then we should firstly stop the player.
this.stopPlayer();
//set the currentSoundIndex to be the index of the selected list item
this.setState({currentSoundIndex: i},() => {
//we need to load the player as a new src has been inserted.
this.loadPlayer();
if(this.state.isPlaying){
//if the player is in a state of playing come here
this.playSound();
}
});
},
goToPreviousSound: function(){
//this function is called when the user presses the back button in the controls.
//firstly disable back button
this.setState({backButtonIsDisabled: true});
var currentIndex = this.state.currentSoundIndex;
var currentTime = this.player.currentTime;
//stop the player. this will set the currentTime to 0 also.
this.stopPlayer();
//navigate to prev sound
},
goToNextSound: function(){
//this function is called when the user presses the forward button in the controls.
//firstly disable forward button
this.setState({forwardButtonIsDisabled: true});
this.stopPlayer();
//it sets the currentIndex to be the next index
var sounds = this.props.route.sounds[0]; //make a copy of the state of the sounds
var currentIndex = this.state.currentSoundIndex;
//navigate to next sound
},
addToFavorites: function (i){
var sounds = this.props.route.sounds[0];
var selectedSound = sounds[i];
this.props.favorites.push(selectedSound);
console.log("fav");
},
render: function() {
return(<div><div id="main-container" className={this.state.sidePanelIsOpen === true ? 'swipe-left' : ''}>
<div className="overlay">
<Header toggleSidePanel={this.toggleSidePanel} sidePanelIsOpen={this.state.sidePanelIsOpen} />
<div className="content">
{this.props.children}
</div>
<AudioPlayer sounds={this.props.route.sounds[0]} currentSoundIndex={this.state.currentSoundIndex} />
<Controls currentWidth={this.state.currentWidthOfTimerBar} currentTime={this.state.currentTime} sounds={this.props.route.sounds[0]} currentSoundIndex={this.state.currentSoundIndex} backButtonIsDisabled={this.state.backButtonIsDisabled} playButtonIsDisabled={this.state.playButtonIsDisabled}
forwardButtonIsDisabled={this.state.forwardButtonIsDisabled}
isPlaying={this.state.isPlaying} playPauseSound={this.playPauseSound}
goBack={this.goToPreviousSound} goForward={this.goToNextSound} />
</div>
</div>
<div id="side-panel-area" class="scrollable">
<div class="side-panel-container">
<div class="side-panel-header"><p>Menu</p></div>
</div>
</div></div>
);
}
});
var Home = React.createClass({
render: function() {
return (
<div>
<h2>Home</h2>
<p>This is the home component</p>
</div>
);
}
});
var Sounds = function(props) {
//this component will take in the currentSoundIndex state as a property and also the sounds array and the selectSound method
return (
<div className="scrollable-container scrollable">
<div id="list-of-sounds-container">
<ul id="list-of-sounds">
{props.sounds.map(function(sound, i) {
//this is the current sound playing so add a class called selected
return (
<li className={"sound-list-item " + (props.currentSoundIndex === i ? 'selected' : 'not-selected')}>
<span className="sound-info-area" onClick={props.selectSound.bind(null, i)}>
<span className="sound-title">{sound.title}</span>
<span className="sound-artist">{sound.artist}</span>
</span>
</li>
);
})}
</ul>
</div>
</div>
);
}
var Controls = function(props) {
//this is a stateless component for the controls-area of the audio player.
//This area is fixed to the bottom of the screen and it contains the Display component, the TimerBar component
//and the controls of the Player i.e back, play/pause and forward.
return (<div id="controls-area">
<div className="overlay">
<Display sounds={props.sounds} currentSoundIndex={props.currentSoundIndex} />
<TimerBar currentWidth={props.currentWidth} currentTime={props.currentTime} sounds={props.sounds} currentSoundIndex={props.currentSoundIndex}/>
<div id="controls">
<button onClick={props.goBack} className="btn-control"><i className="fa fa-backward"></i></button>
<button onClick={props.playPauseSound} className="btn-control" disabled={props.playButtonIsDisabled}><i className={"fa " + (props.isPlaying ? 'fa-pause' : 'fa-play')}></i></button>
<button onClick={props.goForward} className="btn-control" disabled={props.forwardButtonIsDisabled}><i className="fa fa-forward"></i></button>
</div>
</div>
</div>
);
}
ReactDOM.render(<Router history={hashHistory}>
<Route path="/" component={Application} sounds={soundsData} >
<IndexRoute component={Home} />
<Route path="songs" component={Sounds} selectSound={this.selectSound} sounds={this.props.route.sounds[0]} currentSoundIndex={this.state.currentSoundIndex}/>
</Route>
</Router>
,
document.getElementById('application')
);
あなたは 'state'または' methods'を渡さないで 'props'を渡します。 'redux'を使って作業するときには、reduxに接続する各コンポーネントがそれにアクセスでき、' state'という反応を持つ2種類の "状態"を持っています。これは各Reactコンポーネントのプライベートなローカル状態です。メソッドや新しい値を渡したいのですか?あなたはそれを受け取るコンポーネントが新しいデータを扱う責任があります(例えばそれをレンダリングします) –