javascript - 从父组件状态传递时,react prop 未在正确的时间更新

标签 javascript reactjs

我在 React 中遇到了一个非常烦人的错误,并认为它与调用不在我的组件 render 方法之一中的方法有关。我认为我提供了太多的代码,任何人都很难提供帮助,但让我尝试解释我的问题。

我正在进行一个返回 25 个项目的 API 调用。当用户单击“下一步”时,它应该更改背景并播放与背景相关的歌曲。这可行,但是当用户到达列表末尾时我想返回到第一首歌曲。背景图像返回,但播放了错误的歌曲。然后,当用户再次单击时,问题会自行纠正。

我认为问题是由 nextSong 方法中的这一行引起的。

this.audio.src = this.state.songs[this.props.song + 1];

请参阅下面的完整代码。如果有必要,我可以提供一个 github 链接,可以在其中克隆项目,这可能更容易调试。

我知道 SO 不是为了修复其他人的代码,但以防万一我错过了一些我想在这里询问的基本 react 知识。

var App = React.createClass({

    getInitialState: function() {
        return {
              data: [],
              song: 0
        };
    },  

    nextSong: function() {
        if(this.state.song === this.state.data.length) {
            this.setState({song : 0});
        }else{
            this.setState({song : this.state.song += 1});
        }
    },
    previousSong: function() {
        if(this.state.song === 0) {
            this.setState({song : this.state.data.length});
        }else{
            this.setState({song : this.state.song -= 1});
        }
    },
    getData: function(){
        $.ajax({
            url: '...',
            method: 'GET',
            success: function(response){
                this.setState({data: response.items});
            }.bind(this)
        })
    },
    render: function() {
        return(
            <div>
                <BackgroundImage src={this.state.data} image={this.state.song} />
                <Button src={this.state.data} song={this.state.song} nextSong={this.nextSong} previousSong={this.previousSong} />
            </div>
        )
    }
});
    var BackgroundImage = React.createClass({
        render: function() {
            var images = this.props.src.map(function(photo, i){
                return(photo.track.album.images[1].url)
            })
            var divStyle = {
                background: 'url(' + images[this.props.image] + ')'
            }
            return(<div style={divStyle}></div>)
        }
    });

var Button = React.createClass({
    getInitialState: function(){
        return{
            songs:[],
            playing: false
        }
    },

    audio: new Audio,
    playSong: function(){
        this.setState({playing: true});
        this.audio.src = this.state.songs[this.props.song];
        this.audio.play();
    },
    pauseSong: function() {
        this.setState({playing: false});
        this.audio.pause();
    },
    nextSong: function() {
        this.audio.src = this.state.songs[this.props.song + 1];
        this.audio.play();
    },
    onClickNext: function(){
        this.setState({playing: true});
        this.props.nextSong();
        this.nextSong()
    },
    previousSong: function() {
        this.setState({playing: true});
        this.audio.src = this.state.songs[this.props.song - 1];
        this.audio.play();
    },
    onClickPrevious: function(){
        this.props.previousSong();
        this.previousSong()
    },
    render: function() {
        var self = this;
        var songs = this.props.src.map(function(song, i){
            self.state.songs.push(song.track.preview_url)
        });
        return (
            <div className="button">                
                <div className="next" onClick={this.onClickNext}>
                    NEXT
                </div>
                <div className="pause">
                    <p onClick={this.state.playing ? this.pauseSong : this.playSong}></p>
                </div>
                <div className="prev" onClick={this.onClickPrevious}>
                  PREVIOUS
                </div>
            </div>
        )
    }
});

最佳答案

首先,你不应该这样做:

this.setState({song : this.state.song += 1});

因为这将首先设置 this.state.song 然后 setState,这可能会在您更新状态而不提醒 react 时产生一些冲突。我不确定 React 是否能正确处理这个问题。相反,只需执行以下操作:

this.setState({song : this.state.song + 1});

(与-=相同)

回到问题:您应该只在一个地方跟踪当前歌曲。在这种情况下,您应该将其保留在 App 组件的状态中,而按钮组件则不应。 因此,像 nextSong 这样的方法在按钮组件中没有位置。 相反,您可以在 App 组件中更新歌曲(就像在 nextSong 方法中所做的那样),并通过 props 将当前歌曲直接传递到按钮组件。

然后,您可以使用生命周期方法 componentWillReceiveProps 检测当前歌曲是否发生变化,如下所示:

componentWillReceiveProps: function(nextProps) {
    this.playSong(nextProps.song);
}

因此,当您更改 App 中的状态时,它会更新并将新的 props 传递给 Button,然后 Button 将使用新歌曲触发 componentWillReceiveProps 并执行其操作。

关于javascript - 从父组件状态传递时,react prop 未在正确的时间更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39780806/

相关文章:

javascript - 如何旋转整个 SVG 文本对象而不是单个字形

reactjs - React-router 重定向到不同的域 url

javascript - 在 Firefox 中检测关闭窗口事件

javascript - jQuery load() 不存在的页面片段

javascript - 仅在移动设备而非桌面上显示 slider

javascript - React 中的回调参数如何从子组件传递到父组件?

reactjs - 如何导入 GraphQL 查询?

javascript - 使用 React 时如何正确地将事件监听器添加到输入

javascript - 如何在使用 CategoryAxisRenderer 时使用 'ticks' 选项

javascript - react Hook : accessing state across functions without changing event handler function references