张声发 發表於 2026-2-6 11:05:00

面试官:如何解决按钮重复点击?这个问题挂了80%的人!

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<div>
<div>
<h2 data-id="heading-0">前言</h2>
<p>还记得上周我们团队在招聘前端工程师,一个看起来经验丰富的候选人坐在我对面。</p>
<p>"你们项目中是如何处理按钮重复点击的问题的?"我抛出了这个看似简单的问题。</p>
<p>"这个简单,使用防抖就可以了。"他很快回答。</p>
<p>然而,当我继续追问细节时,他却陷入了沉思...</p>
<p>实际上,这个问题看似简单,但是要真正的解决好,需要考虑很多细节。在我面试了很多候选人中,能完整答出来的不到20%。</p>
<h2 data-id="heading-1">问题背景</h2>
<p>在日常开发中,我们经常会遇到这样的场景:</p>
<ul>
<li>用户疯狂点击提交按钮</li>
<li>表单重复提交导致数据异常</li>
<li>批量操作按钮被连续触发</li>
</ul>
<p>这些问题如果处理不当,轻则影响用户体验,重则可能造成数据错误。今天,就让我们通过一个真实的面试场景,逐步深入这个问题</p>
<h2 data-id="heading-2">面试场景</h2>
<p>面试官:项目中如何处理按钮重复点击的问题?</p>
<p>候选人:可以使用防抖(debounce)。</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">const debouncedSubmit = debounce(submit, 300);</pre>
</div>
<div>
<div>
<p>面试官:那假设我防抖设置了1秒,我现在请求了,但是接口响应比较慢,要3秒,用户在这3秒内点击了多次,那怎么办? 防抖是不是就没用了?</p>
<blockquote>
<p>一般说到这里,很多人就不知道怎么搞了</p>
</blockquote>
<p>候选人:可以给按钮加上 loading 状态,点击后设置 loading 为 true,等操作完成后再设置为 false。</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">const = useState(false);

const handleSubmit = async () =&gt; {
    setLoading(true);
    try {
      await submitData();
    } finally {
      setLoading(false);
    }
}</pre>
</div>
<div>
<div>
<p>面试官:这个思路不错,但是如果项目中有很多按钮都需要这样处理,你会怎么做?</p>
<p>候选人:额...每个按钮都写一遍 loading 状态管理?</p>
<p>面试官:那样就会有很多重复代码,有没有想过怎么封装呢?</p>
<blockquote>
<p>到这里也卡掉了很多人</p>
</blockquote>
<h2 data-id="heading-3">解决方案</h2>
<p>我们可以封装一个自定义 Hook</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">import {useState,useCallback,useRef} from 'react'

function useLock(asyncFn) {
    const = useState(false)
    const asyncFnRef = useRef(null)
    asyncFnRef.current = asyncFn
    const run = useCallback(async (...args) =&gt; {
      if(loading) return
      setLoading(true)
      try {
            await asyncFnRef.current(...args)
      } finally {
            setLoading(false)
      }
    }, )

    return
}</pre>
</div>
<p>然后封装一个通用的 Button 组件</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">import {Button as AntButton} from 'antd'

const Button = ({onClick,...props})=&gt;{
    const {loading, run} = useLock(onClick || (()=&gt; {}))
    return &lt;AntButton loading={loading} {...props} onClick={run}&gt;&lt;/button&gt;
}</pre>
</div>
<h2 data-id="heading-4">使用示例</h2>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">const Demo = () =&gt; {
    const handleSubmit = async () =&gt; {
      // 模拟异步请求
      await new Promise(resolve =&gt; setTimeout(resolve, 2000))
      console.log('提交成功')
    }

    return (
      &lt;Button onClick={handleSubmit}&gt;
            提交
      &lt;/Button&gt;
    )
}</pre>
</div>
<div>
<div>
<p>可以看到 在 handleSubmit 执行的时候 Button 会自动添加 loading, 在请求完成后 loading 会自动变为 false。</p>
<h2 data-id="heading-5">方案优势</h2>
<ul>
<li>零侵入性 :使用方式与普通按钮完全一致</li>
<li>自动处理 :自动管理 loading 状态,无需手动控制</li>
</ul>
<p>希望这篇文章对你有帮助!如果觉得有用,别忘了点个赞 👍</p>
<h2 data-id="heading-6">讨论</h2>
<p>你在项目中是如何处理按钮重复点击的问题的?欢迎在评论区分享你的解决方案!</p>
</div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p>
</div>
</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19583147
頁: [1]
查看完整版本: 面试官:如何解决按钮重复点击?这个问题挂了80%的人!