React Rails - Like 按钮状态未正确更新
React Rails - Like button state not updating properly
我有一个供稿,您可以在其中 post 个条目。然后任何用户都可以喜欢这些条目。问题是,在你喜欢一个条目并继续写你自己的条目之后(从而将新条目推到 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>
);
}
}
在父组件'log_entry.es6.jsx'中,我按以下方式添加了我喜欢的组件:
<Like entry={entry} key={entry.id} />
如果有更多信息我可以提供,我会很乐意根据要求提供。感谢您花时间查看我的问题!
当您 "continue with writing your own entry" 时,会更新 parent 组件中的 this.state
吗?如果是这样,我敢打赌它会导致 Like
到 re-render 及其道具,这些道具已变成 out-of-date!
这样想:传递给 <Like entry={entry} />
的 entry
只包含初始页面加载时为真的数据。当用户单击 "like" 时,它会更新 Like
组件的 this.date
,但 原始 entry
是 未更新!
因此,如果某些原因导致 Like
从 entry
变为 re-render,它将使用陈旧数据呈现!但是,如果您刷新页面,它将获取最新数据并正确呈现。
这听起来像是一个可能的原因吗?
我能想到的最佳解决方案是 container component 模式。在这个模式中,只有一个组件(在树的顶部)有this.state
。它将数据作为道具发送到它的 children。只有容器组件发送 AJAX 请求和更新 this.state
.
在您的情况下,这意味着将 post
和 delete
函数移动到 parent 组件,并将它们作为事件处理程序传递给 Like
(例如, <Like onLike={this.post} onUnlike={this.delete} ...>
) 然后,在 Like
中,您可以将它们用作 on-click 处理程序,例如 onClick={this.onLike}
.
虽然这需要仔细组织,但它确实值得,因为每个 render
都是非常可预测的:唯一可以改变的是容器的 this.state
,其他所有内容都从 this.props
呈现只有!
我尝试将函数和状态处理程序移动到父组件。然而,事实证明这很麻烦,因为我的“赞”按钮的父级也有一个父级(也许我可以进一步用尽这个方法,但我找到了不同的方法)。
我的解决方案最终是这样的:
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 和删除函数上添加了 2 行。
this.props.entry.liked = true;
this.props.entry.likes_count = likes;
this.props.entry.liked = false;
this.props.entry.likes_count = likes;
只是更新此条目的道具。我不确定这是否是最好的解决方案,但对我来说,它帮助我保留了它所属的功能,当然它也可以工作。
我有一个供稿,您可以在其中 post 个条目。然后任何用户都可以喜欢这些条目。问题是,在你喜欢一个条目并继续写你自己的条目之后(从而将新条目推到 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>
);
}
}
在父组件'log_entry.es6.jsx'中,我按以下方式添加了我喜欢的组件:
<Like entry={entry} key={entry.id} />
如果有更多信息我可以提供,我会很乐意根据要求提供。感谢您花时间查看我的问题!
当您 "continue with writing your own entry" 时,会更新 parent 组件中的 this.state
吗?如果是这样,我敢打赌它会导致 Like
到 re-render 及其道具,这些道具已变成 out-of-date!
这样想:传递给 <Like entry={entry} />
的 entry
只包含初始页面加载时为真的数据。当用户单击 "like" 时,它会更新 Like
组件的 this.date
,但 原始 entry
是 未更新!
因此,如果某些原因导致 Like
从 entry
变为 re-render,它将使用陈旧数据呈现!但是,如果您刷新页面,它将获取最新数据并正确呈现。
这听起来像是一个可能的原因吗?
我能想到的最佳解决方案是 container component 模式。在这个模式中,只有一个组件(在树的顶部)有this.state
。它将数据作为道具发送到它的 children。只有容器组件发送 AJAX 请求和更新 this.state
.
在您的情况下,这意味着将 post
和 delete
函数移动到 parent 组件,并将它们作为事件处理程序传递给 Like
(例如, <Like onLike={this.post} onUnlike={this.delete} ...>
) 然后,在 Like
中,您可以将它们用作 on-click 处理程序,例如 onClick={this.onLike}
.
虽然这需要仔细组织,但它确实值得,因为每个 render
都是非常可预测的:唯一可以改变的是容器的 this.state
,其他所有内容都从 this.props
呈现只有!
我尝试将函数和状态处理程序移动到父组件。然而,事实证明这很麻烦,因为我的“赞”按钮的父级也有一个父级(也许我可以进一步用尽这个方法,但我找到了不同的方法)。
我的解决方案最终是这样的:
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 和删除函数上添加了 2 行。
this.props.entry.liked = true;
this.props.entry.likes_count = likes;
this.props.entry.liked = false;
this.props.entry.likes_count = likes;
只是更新此条目的道具。我不确定这是否是最好的解决方案,但对我来说,它帮助我保留了它所属的功能,当然它也可以工作。