React Rails - 类似按钮状态未正确更新

时间:2016-02-14 18:17:43

标签: ruby-on-rails reactjs react-rails

我所拥有的是一个可以发布条目的Feed。然后,任何用户都可以喜欢这些条目。问题是,在您喜欢一个条目并继续编写自己的条目之后(因此将新条目推送到Feed的顶部),您单击的所有类似按钮的状态将在视觉上撤消,以便看到显示的正确数据需要手动刷新。

这个问题非常奇怪,遗憾的是我找不到任何可能与此相关的内容。

这是我的Like组件的代码(like.es6.jsx):

class Like extends React.Component {
    constructor(props){
        super(props);
        this.state={
            like: this.props.entry.liked,
            likes: this.props.entry.likes_count
        }
        this.post = this.post.bind(this);
        this.delete = this.delete.bind(this);
    }

    post () {
        if(!(this.state.like)){
            $.ajax({
                    method: "POST",
                    url: "/api/v1/likes",
                    data: {
                        log_entry_id: this.props.entry.id
                    },
                })
                .then( (response) => {
                    this.setState({like: true})
                    let likes = this.state.likes;
                    likes++;
                    this.setState({likes: likes})
                });
        }
    }

    delete(){
        if(this.state.like){
            $.ajax({
                    method: "DELETE",
                    url: "/api/v1/likes/" + this.props.entry.id
                })
                .then( (response) => {
                    this.setState({like: false})
                    let likes = this.state.likes;
                    likes--;
                    this.setState({likes: likes})
                });
        }
    }

    render () {
        let show_likes = "";
        if(this.state.like) {
            show_likes = (this.state.likes > 1) ? ("You and " + (this.state.likes - 1) + ((this.state.likes == 2) ? (" other person") : (" others" )) + (" like this.")) : ("You like this.");
        }else if(this.state.likes > 0){
            show_likes = (this.state.likes == 1) ? (this.state.likes + " person likes this.") : (this.state.likes + " people like this.");
        }
        let like_button = this.state.like ?
            <a onClick={this.delete} className=" pull-right"><i className="fa fa-thumbs-o-down"></i> Dislike</a> :
            <a onClick={this.post} className=" pull-right"><i className="fa fa-thumbs-o-up"></i> Like</a>
        return (
            <div>
            <span>
                {show_likes}
            </span>
                {like_button}
            </div>
        );
    }
}

在父组件&#39; log_entry.es6.jsx&#39;我已通过以下方式添加了我喜欢的组件:

<Like entry={entry} key={entry.id} />

如果我能提供更多信息,我会很乐意应要求提供。感谢您抽出时间审核我的问题!

2 个答案:

答案 0 :(得分:1)

当您“继续编写自己的条目”时,是否会在父组件中更新this.state?如果是这样,我敢打赌它会导致Like重新渲染其道具,这些道具已经过时了!

以这种方式思考:传递到entry的{​​{1}}仅包含在初始页面加载时为真的数据。当用户点击“赞”时,它会更新<Like entry={entry} />组件的this.date,但原始 Like 更新!

因此,如果某些内容导致entryLike重新渲染,则会使用陈旧数据进行渲染!但是,如果刷新页面,它将获取最新数据并正确呈现。

这听起来像是一个可能的原因吗?

我能想到的最佳解决方案是container component模式。在此模式中,只有一个组件(位于树的顶部)具有entry。它将数据作为道具发送给子项。只有容器组件发送AJAX请求并更新this.state

在您的情况下,这意味着将this.statepost函数移动到父组件,并将它们作为事件处理程序传递给delete(例如,Like然后,在<Like onLike={this.post} onUnlike={this.delete} ...>中,您可以将它们用作点击式处理程序,例如Like

虽然这需要精心组织,但它确实是值得的,因为每个onClick={this.onLike}都是可预测的:唯一可以改变的是容器的render,其他所有内容只能从this.state呈现!

答案 1 :(得分:0)

我尝试将函数和状态处理程序移动到父组件。然而事实证明这很麻烦,因为我的Like按钮的父母也有一个父母(也许我可以进一步用尽这种方法,但我发现了一种不同的方式)。

我的解决方案最终成为了这个:

class Like extends React.Component {
    constructor(props){
        super(props);
        this.state={
            like: this.props.entry.liked,
            likes: this.props.entry.likes_count
        }
        this.post = this.post.bind(this);
        this.delete = this.delete.bind(this);
    }

    post () {
        if(!(this.state.like)){
            $.ajax({
                    method: "POST",
                    url: "/api/v1/likes",
                    data: {
                        log_entry_id: this.props.entry.id
                    },
                })
                .then( (response) => {
                    this.setState({like: true})
                    let likes = this.state.likes;
                    likes++;
                    this.setState({likes: likes});
                    this.props.entry.liked = true;
                    this.props.entry.likes_count = likes;
                });
        }
    }

    delete(){
        if(this.state.like){
            $.ajax({
                    method: "DELETE",
                    url: "/api/v1/likes/" + this.props.entry.id
                })
                .then( (response) => {
                    this.setState({like: false})
                    let likes = this.state.likes;
                    likes--;
                    this.setState({likes: likes});
                    this.props.entry.liked = false;
                    this.props.entry.likes_count = likes;
                });
        }
    }

    render () {
        let show_likes = "";
        if(this.state.like) {
            show_likes = (this.state.likes > 1) ? ("You and " + (this.state.likes - 1) + ((this.state.likes == 2) ? (" other person") : (" others" )) + (" like this.")) : ("You like this.");
        }else if(this.state.likes > 0){
            show_likes = (this.state.likes == 1) ? (this.state.likes + " person likes this.") : (this.state.likes + " people like this.");
        }
        let like_button = this.state.like ?
            <a onClick={this.delete} className=" pull-right"><i className="fa fa-thumbs-o-down"></i> Dislike</a> :
            <a onClick={this.post} className=" pull-right"><i className="fa fa-thumbs-o-up"></i> Like</a>
        return (
            <div>
            <span>
                {show_likes}
            </span>
                {like_button}
            </div>
        );
    }
}

我在post和delete函数中添加的是2行。

this.props.entry.liked = true;
this.props.entry.likes_count = likes;

this.props.entry.liked = false;
this.props.entry.likes_count = likes;

只需更新此条目的道具即可。我不确定这是否是最好的解决方案,但对我而言,这有助于我保留其所属的功能,当然它也可以。