React中如何延迟重复触发的服务端请求?
待办复选框频繁触发重复请求的防抖方案
你需要的延迟发请求效果用防抖(debounce)逻辑实现即可:用户停止操作300ms后才真正发起请求,操作过程中反复勾选/取消只会重置等待计时,不会发送无效请求。
注意:你原有代码里的
setTodos([response.data])存在逻辑问题,会把整个待办列表覆盖成单条数据,下面的修复代码会一并修正这个问题。
核心实现逻辑
- 用
useRef存储不同待办项对应的定时器ID,避免组件重渲染时丢失定时器引用 - 每次复选框状态变更时,先清除当前待办项之前挂起的未发送请求定时器
- 重新启动300ms倒计时,倒计时结束后再向服务端发送更新请求
- 接口返回后匹配待办ID,只更新对应项的完成状态,保留列表其余数据
- 可选优化:组件卸载时清除所有未执行的定时器,避免内存泄漏
完整修改后代码
import React, { useState, useRef, useEffect } from 'react'; import axios from 'axios'; const Form = () => { const [todos, setTodos] = useState([]); // 存储每个todo对应的定时器 const timerRef = useRef({}); // 组件卸载时清除所有未执行的定时器 useEffect(() => { return () => { Object.values(timerRef.current).forEach(timer => clearTimeout(timer)); } }, []); const completedOnChangeHandler = (e, id) => { const checked = e.target.checked; // 清除当前todo之前未发送的请求定时器 if (timerRef.current[id]) { clearTimeout(timerRef.current[id]); } // 设置新的300ms延迟请求 timerRef.current[id] = setTimeout(() => { axios .patch(`http://127.0.0.1:8000/todo/todos/${id}/`, { completed: checked, }) .then( (response) => { console.log(response.data); // 修正原有状态更新逻辑:只替换对应id的todo项 setTodos(prev => prev.map(todo => todo.id === id ? response.data : todo )); }, (error) => { console.log(error); } ); }, 300); }; return ( <form> {todos.map((todo) => ( <ul key={todo.id}> <li>{todo.title}</li> <li>{todo.description}</li> <button>delete</button> <input type="checkbox" placeholder="completed" onChange={(e) => completedOnChangeHandler(e, todo.id)} checked={todo.completed} /> </ul> ))} </form> ); }; export default Form;
效果说明
- 用户快速反复勾选/取消同一个复选框时,只有最后一次操作结束后等待300ms才会发送请求,中间的操作都不会触发接口调用
- 不同待办项的定时器互相独立,操作A待办的复选框不会影响B待办的待发请求
- 修复了原代码状态更新会覆盖整个列表的bug,列表渲染逻辑正常
内容的提问来源于stack exchange,提问作者Matin
相关产品推荐
相关产品推荐

