如何在React Textarea中实现防抖?解决输入延迟问题
解决React输入防抖导致的延迟问题
你遇到的核心矛盾是:防抖setCommentBody会让组件状态延迟更新,导致textarea显示跟不上输入节奏。要兼顾实时输入显示和减少重渲染,可以通过分离「实时输入存储」和「防抖状态更新」来解决:
具体实现步骤
- 使用
useRef存储实时输入值,保证textarea能实时显示用户输入的内容 - 对
setCommentBody进行防抖,仅在用户停止输入一段时间后更新组件状态,减少重渲染次数 - 清理防抖函数,避免组件卸载后残留执行逻辑
修改后的完整代码
import { debounce } from "lodash"; import { useState, useRef, useCallback, useEffect } from "react"; import ReviewCard from "../ReviewCard/ReviewCard"; const CommentInput = ({ postId, userId, onCommentChange, onCommentSubmit }) => { const dispatch = useDispatch(); const [commentBody, setCommentBody] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); const [submittedText, setSubmittedText] = useState(""); const [submittedComments, setSubmittedComments] = useState([]); const inputRef = useRef(""); // 存储实时输入值 console.log(commentBody); // 现在只会在停止输入300ms后打印 // 用useCallback包裹防抖函数,避免每次重渲染创建新实例 const debouncedUpdateCommentBody = useCallback( debounce((value) => { setCommentBody(value); }, 300), [] ); const handleInputChange = (e) => { const value = e.target.value; inputRef.current = value; // 实时更新ref,保证textarea显示最新内容 debouncedUpdateCommentBody(value); // 防抖更新组件状态 }; // 组件卸载时清理防抖函数 useEffect(() => { return () => debouncedUpdateCommentBody.cancel(); }, [debouncedUpdateCommentBody]); const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); setIsSubmitting(true); // 提交时直接用ref的实时值,避免依赖延迟更新的state const submitValue = inputRef.current; const newComment = await dispatch( postComment({ body: submitValue, postId, userId }) ); setSubmittedText(submitValue); setIsSubmitting(false); onCommentChange(""); onCommentSubmit(newComment.payload); setSubmittedComments([...submittedComments, newComment]); // 重置state和ref setCommentBody(""); inputRef.current = ""; }; return ( <div className={st.add_comment}> {submittedComments.map((comment, index) => ( <ReviewCard key={index} reviewerName={`@${comment.payload.user.username}`} commentary={submittedText} /> ))} <Text type={"h3"}> Add <span className={st.highlight}> comment </span> </Text> <form className={st.add_comment_form} onSubmit={handleSubmit}> <textarea className={st.add_comment_input} ref={inputRef} defaultValue={commentBody} onChange={handleInputChange} placeholder="ENTER YOUR COMMENT" disabled={isSubmitting} /> <Button type={"primary"} disabled={isSubmitting || !inputRef.current.trim()}> {isSubmitting ? "Posting..." : "Send"} </Button> </form> </div> ); }; export default CommentInput;
关键说明
- 用
inputRef实时同步用户输入,textarea使用非受控模式(defaultValue),保证输入显示无延迟 - 防抖仅作用于
setCommentBody,组件只会在用户停止输入300ms后才重渲染,减少不必要的更新 - 提交时直接读取
inputRef.current的值,避免依赖延迟更新的commentBody状态 - 添加防抖函数的清理逻辑,防止组件卸载后仍执行状态更新
内容的提问来源于stack exchange,提问作者aftab
相关产品推荐
相关产品推荐

