javascript - React.js,如何立即呈现用户动作(在等待服务器传播之前)
问题描述
我正在构建一个购物清单网络应用程序。列表中的项目可以切换为“选中”或“未选中”。
我的数据流是这样的:单击项目复选框 --> 发送数据库更新请求 --> 使用新的复选框状态重新呈现列表数据。
如果我完全在反应本地组件状态中处理复选框状态,则用户操作更新非常快。
快速演示:https ://youtu.be/kPcTNCERPAo
但是,如果我等待服务器传播,更新会显得很慢。
慢速演示:https ://youtu.be/Fy2XDUYuYKc
我的问题是:如何使复选框动作立即出现(使用本地组件状态),同时如果另一个客户端更改数据库数据,还更新复选框状态。
这是我的尝试(React 组件):
import React from 'react';
import ConfirmModal from '../ConfirmModal/ConfirmModal';
import {GrEdit} from 'react-icons/gr';
import {AiFillDelete, AiFillCheckCircle} from 'react-icons/ai';
import {MdRadioButtonUnchecked} from 'react-icons/md';
import './ListItem.scss';
class ListItem extends React.Component{
constructor(props){
super(props);
this.state = {
confirmOpen: false,
checkPending: false,
itemChecked: props.item.checked,
};
}
static getDerivedStateFromProps(nextProps, prevState){
if(nextProps.item.checked != prevState.itemChecked){
return ({itemChecked: nextProps.item.checked})
}
return null;
}
render(){
return (
<div className={`listItemWrapper${this.state.itemChecked ? ' checked': ''} `}>
{this.state.confirmOpen ?
<ConfirmModal
triggerClose={() => this.setState({confirmOpen: false})}
message={`Do you want to delete: ${this.props.item.content}?`}
confirm={() => {
this.clickDelete();
this.setState({confirmOpen: false});
}}
/> : null
}
<div className="listItem">
<div className='listContent'>
{ this.state.itemChecked ?
<strike>{this.props.item.content}</strike>
: this.props.item.content
}
<div className={`editBtn`}>
<GrEdit onClick={() => {
let {content, category, _id} = this.props.item;
this.props.edit({content, category, _id});
}}
/>
</div>
</div>
</div>
<div className={`listToolsWrapper`}>
<div className = "listTools">
<div onClick={() => this.setState({confirmOpen: true})} className={`tool`}><AiFillDelete className="listItemToolIcon deleteIcon"/></div>
<div onClick={() => !this.state.checkPending ? this.clickCheck() : null} className={`tool`}>
{this.state.itemChecked ? <AiFillCheckCircle className="listItemToolIcon checkIcon"/> : <MdRadioButtonUnchecked className="listItemToolIcon checkIcon"/>}
</div>
</div>
<div className = "listInfo">
<div className ="itemDate">
{this.props.item.date}
{this.props.item.edited ? <p className="edited">(edited)</p> : null}
</div>
</div>
</div>
</div>
);
}
async clickCheck(){
this.setState(prevState => ({checkPending: true, itemChecked: !prevState.itemChecked}));
await fetch(`/api/list/check/${this.props.item._id}`,{method: 'POST'});
this.setState({checkPending: false});
//fetch updated list
this.props.fetchNewList();
}
async clickDelete(){
await fetch(`/api/list/${this.props.item._id}`,{method: 'DELETE'});
//fetch updated list
this.props.fetchNewList();
}
}
export default ListItem;
我对如何在这里正确使用反应生命周期方法感到困惑。我正在使用本地状态来镜像组件道具。我尝试使用 getDerivedStateFromProps() 来同步状态和道具,但这并不能使渲染更快。
解决方案
您尝试实现的效果称为Optimistic UI,这意味着当某些异步操作发生时,您正在伪造该操作成功的效果。
例如。Facebook Like 功能 1. 当您在 Facebook 帖子上单击 Like 时,计数会自动增加一(您),然后在后台将 ajax 请求发送到 API。2. 当你从你的 ajax 请求中得到响应时,你会知道它是成功还是失败。如果成功,那么您可以选择什么都不做,但如果失败,您可能希望减少之前添加的点赞数,并向用户显示一些错误(或不显示)。
在您的情况下,您可以做同样的事情,但如果您想要实时更新,您需要创建一些解决方案,如长轮询或web sockets .co
此外,您提供的getDerivedStateFromProps看起来不错。
推荐阅读
- java - 为什么我无法访问基类中的重写方法?
- d3.js - 如何在字母而不是数字上应用补间函数?
- winston - 温斯顿记录器 2 到 3 升级。逗号分隔的消息不再连接
- nativescript - 在 iOS 中下载文件
- python - 如何从 python 中使用 Qt 的“图形视图”框架?
- c# - MVC中有什么不能在webform中实现的吗
- c# - 为什么它不起作用?StartupLocation = WPF 中的 CenterOwner
- c++ - I can't access my winsock server from another computer (but localhost works)
- python - 在 Cloud Build 管道中运行 python 测试的最佳做法是什么?
- jquery - 我们可以在使用 jQuery QueryBuilder 时在多个规则之间添加 AND/OR 吗?不使用组的库