在jsbin完成工作示例: http://jsbin.com/tepedepozi/1/edit?console,output
_____________________________________________________________--
我有一个名为App的组件,完整返回的JSX就在这里:
<main style = {mainContainer}>
<Loader/>
<section style={goldPanel}>
<TimeDisplay isPlaying = {this.state.isPlaying}/>
<div className="buttonContainer">
<Button buttonText = {this.state.recordButtonText} onClick={this.toggleRecording}/>
<Button buttonText = {this.state.playButtonText} onClick={this.toggleSongPlaying} />
</div>
</section>
</main>
请注意,有两个按钮:录制按钮和播放按钮
然后用户点击播放按钮:
<Button buttonText = {this.state.playButtonText} onClick={this.toggleSongPlaying} />
调用将this.state.isPlaying
更改为true
的方法:
如果用户点击了记录按钮,它根本不会改变this.state.isPlaying
- 永远!这是我编程的方式,这是我想要的行为!
在TimeDisplay
组件中,我将this.state.isPlaying
的状态作为道具传递。
<TimeDisplay isPlaying = {this.state.isPlaying}/>
问题在于我想让TimeDisplay以基于此状态的方式运行,而TimeDisplay组件应该只根据用户点击来响应状态更改:
<Button buttonText = {this.state.playButtonText} onClick={this.toggleSongPlaying} />
但是,当用户单击播放按钮然后记录按钮时,记录按钮会强制在TimeDisplay组件上重新呈现。我通过在下面的startCount()
方法代码中放置一个setInterval来证明这个问题。
TimeDisplay组件:
class TimeDisplay extends React.Component {
constructor(props) {
super(props)
}
startCounter(){
if(this.props.isPlaying){
console.log("counter working"); // runs no matter what button is clicked after play button
setInterval(()=>{
console.log("Multiple setIntervals get invoked when user clicks record...not good");
},1000)
}
}
render() {
this.startCounter() //______Due to rerender. How to fix ?
return (
<div>
<p><span id="seconds">00</span>:<span id="tens">00</span></p>
</div>
)
}
}
答案 0 :(得分:1)
您需要在componentDidMount方法中编写this.startCounter()
函数,而不是在渲染中编写,因为setInterval将为您完成工作,您只需要调用setInterval一次而不是每次渲染。既然是从道具收到了播种,你还需要更新你的孩子柜台。您可以在componentDidUpdate中执行此操作,如
class TimeDisplay extends React.Component {
constructor(props) {
super(props)
this.interval = null;
}
componentDidMount() {
this.startCounter();
}
componentDidUpdate(prevProps) {
if(prevProps.isPlaying !== this.props.isPlaying) {
this.startCounter();
}
}
startCounter() {
if (this.props.isPlaying) {
this.interval = setInterval(() => {
console.log("Multiple setIntervals get invoked when user clicks record...not good");
}, 1000);
}else{
clearInterval(this.interval);
}
}
render() {
return (
<div>
<p><span id="seconds">00</span>:<span id="tens">00</span></p>
</div>
)
}
}
class Button extends React.Component {
constructor(props) {
super(props)
}
render() {
return (<button onClick={this.props.onClick}>{this.props.buttonText}</button>)
}
}
<强> Working JSBIN 强>
P.S。我使用
componentDidUpdate
而不是。{componentWillReceiveProps
因为React建议他们愿意 从componentWillReceiveProps
开始重命名v16.3.0
并删除 从第17节开始。查看this对话
答案 1 :(得分:0)
您需要在触发新内容之前取消间隔。另外@shubham建议像他建议的那样调用startCounter
方法。
constructor(props) {
super(props)
this.timeInterval = null;
}
}
componentWillUnmount(){
if(this.timeInterval != null){
clearInterval(this.timeInterval)// Clear interval on page unmount
}
}
startCounter(){
if(this.timeInterval != null){
clearInterval(this.timeInterval)// Cancel interval if it is being executing.
}
if(this.props.isPlaying){
console.log("counter working"); // runs no matter what button is clicked after play button
this.timeInterval = setInterval(()=>{
console.log("Multiple setIntervals get invoked when user clicks record...not good");
},1000)
}
}
componentDidMount() {
this.startCounter() // Call on initial render
}
componentWillReceiveProps(){
this.startCounter() //call on props change
}
render() {
return (
<div>
<p><span id="seconds">00</span>:<span id="tens">00</span></p>
</div>
)
}
}