javascript - 如果已经有一个 API 调用正在进行,如何确保我不会再次调用我的 API(通过单击按钮)?
问题描述
我制作了这段代码,我对此有疑问。
在阅读问题之前,请参阅下面的片段。
它通过调用 API 来模仿博客文章的喜欢/不喜欢行为,我认为它按预期工作,但我不知道具体原因。我认为这很有趣。
这是我的思路:
- 一切渲染后,我在按钮上附加了一个“点击”侦听器,它将由我的函数处理
toggleLike
- 在我第一次单击按钮之前,我的
toggleLike
函数,此时,它是在最后一次渲染期间创建的props.likeInProgress
,当时的值为false
。因此,如果我此时执行这个函数 10 次,它会执行的思想props.likeInProgress
就是false
. - 我知道一旦单击按钮,首先要做的就是通过调用
toggleLike
将其设置likeInProgress
为,这将阻止我在另一个之上进行两个 API 调用。true
setLikeInProgress(true);
- 但我也知道这
setState
可能不会立即触发重新渲染,那么是什么阻止我疯狂地快速点击并最终同时调用 API 两次或三次?
问题
事实是,似乎不可能足够快地单击并同时触发多个 API 调用(同时运行)。这就是我想要实现的目标。
但我想知道的是:这是速度问题吗?React 更新状态的速度是否如此之快,以至于在重新创建之前无法再次单击按钮(现在为 true)?toggleFunction
props.likeInProgress
还是代码执行的顺序完全阻止了这种情况的发生,与速度无关?
更多解释:
当您真正快速单击 2 次时,您看到该日志的事实There is a call in progress
意味着 React 已经重新渲染了所有内容,现在该toggleLike
函数显示props.likeInProgress
为true
. 如果这是速度问题,并且您单击得非常快,那么您将能够toggleLike
从第一次单击时执行相同的操作,这props.likeInProgress
将false
导致您再次调用 API。
function App() {
//console.log('Rendering App...');
// STATE TO MONITOR THE LIKE API CALL IN PROGRESS
const [likeInProgress,setLikeInProgress] = React.useState(false);
// STATE TO KNOW WHETHER A POST HAS BEEN LIKED OR NOT
const [hasLiked,setHasLiked] = React.useState(false);
// REF TO KEEP TRACK OF THE LIKE COUNT
const likeCount_ref = React.useRef(15);
// THIS IS TO MOCK A LIKE API CALL (1000 ms DELAY ASYNC)
function mockLikeAPI(action) {
return new Promise((resolve,reject) => {
setTimeout(()=>{
resolve('Done');
},1000);
});
}
// THIS IS THE CALL TO THE LIKE API
function callMockLikeAPI(action) {
setLikeInProgress(true); // SET STATE likeInProgress TO 'TRUE'
mockLikeAPI(action).then(()=> { // CALL THE API
likeCount_ref.current = action === 'LIKE' ? // UPDATE COUNTER ACCORDINGLY
likeCount_ref.current + 1
: likeCount_ref.current - 1;
action === 'LIKE' ? setHasLiked(true) : setHasLiked(false); // UPDATE hasLiked STATE
setLikeInProgress(false);
});
}
return(
<BlogPost
likeCount={likeCount_ref.current}
likeInProgress={likeInProgress}
hasLiked={hasLiked}
callMockLikeAPI={callMockLikeAPI}
/>
);
}
function BlogPost(props) {
//console.log('Rendering BlogPost...');
// FUNCTION TO TOGGLE THE LIKE OF THE POST
function toggleLike() {
if (props.likeInProgress) { // IF THERE'S A LIKE IN PROGRESS
console.log('There is a call in progress...'); // LOG
return; // DO NOTHING. RETURN;
}
else { // ELSE
console.log('I will call the API now...'); // LOG
props.hasLiked === false ? // CALL THE API WITH THE PROPER ACTION
props.callMockLikeAPI('LIKE')
: props.callMockLikeAPI('DISLIKE');
}
}
return(
<React.Fragment>
<div>I am a Blog Post</div>
<div>Like Count: {props.likeCount}</div>
<button onClick={toggleLike}>{props.hasLiked === false ? 'Like' : 'Dislike'}</button>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
解决方案
用户单击按钮后隐藏按钮,将其替换为 gif 加载器,然后在调用完成后再次显示。您将需要在网络调用上实现回调。这将保证用户不能call the api twice
因为带有 onclick 事件的按钮现在被隐藏。
btnWithNetCall(parameter1){
// hide your button via attribute or css
attemptAPIcall(param1, function(response){
//show your button again after checking what happened with response
})
}
attemptAPIcall(param1, callback){
// fire callback with pertinent data after doing networky thing
callback(someSortOfReponseData)
}
推荐阅读
- python - Pandas 将小时日期 excel 表重新排列为日期时间数据框
- excel - 如何在 2 个不同选项卡上的一个 Excel 中通过 SSRS 报告导出摘要和详细信息钻取
- github - 避免在 git pull 中获取少数版本文件的更新
- angular - AgGrid 更新到 v19,我做错了什么?
- ios - 如何将 SDWebImage 转换为 UIImage?
- python - 如何正确使用来自 lxml 的 xmlfile api
- javascript - CodeSignal 挑战:电话
- sql-server - 使用 CASE 语句和 GROUP BY 子句的 LAST_VALUE 聚合函数
- xml - XSLT:如何检查全局婴儿车外部的 NULL 值
- variables - 如何读取 txt 文件并使用其数据与其他变量进行比较?