React Native中使用Lodash Debounce处理TextInput触发异常问题
React Native TextInput防抖失效问题解决
我需要实现React Native的TextInput在输入停止500毫秒后才向API发送请求,但当前每次输入字符都会触发Lodash防抖函数,达不到预期效果。
问题代码
import { debounce } from "lodash"; import React, { FC, useState } from "react" import { TextInput, View } from "react-native" interface Props { } const LodashInputComponent: FC<Props> = (props) => { const [searchText, setSearchText] = useState(""); const onDebounceSearch = debounce((value: string) => { console.log("API Send request", value); }, 500); const onChangeSearchText = (val: string) => { console.log("Change search text", val); setSearchText(val); onDebounceSearch(val); }; return ( <View> <TextInput value={searchText} onChangeText={onChangeSearchText} placeholder="Search" /> </View> ) } export default LodashInputComponent;
控制台输出(不符合预期)
Change search text h Change search text he API Send request h API Send request he Change search text hel Change search text hell API Send request hel Change search text hello API Send request hell API Send request hello Change search text hello Change search text hello w Change search text hello wo API Send request hello API Send request hello w Change search text hello wor API Send request hello wo API Send request hello wor Change search text hello worl Change search text hello world API Send request hello worl API Send request hello world
问题原因
函数组件每次执行(比如调用setSearchText更新state时)都会重新创建onDebounceSearch防抖函数实例。这意味着每次输入字符触发组件重新渲染后,都是在调用一个全新的防抖函数,之前的防抖计时被重置,导致每个字符输入都会触发API请求。
解决方案
方法1:使用useCallback缓存防抖函数
通过useCallback将防抖函数缓存,确保组件渲染时不会重复创建新的防抖实例,同时在组件卸载时清理防抖任务避免内存泄漏。
import { debounce } from "lodash"; import React, { FC, useState, useCallback, useEffect } from "react" import { TextInput, View } from "react-native" interface Props {} const LodashInputComponent: FC<Props> = (props) => { const [searchText, setSearchText] = useState(""); // 用useCallback缓存防抖函数,依赖项为空确保只创建一次 const onDebounceSearch = useCallback( debounce((value: string) => { console.log("API Send request", value); }, 500), [] ); const onChangeSearchText = (val: string) => { console.log("Change search text", val); setSearchText(val); onDebounceSearch(val); }; // 组件卸载时取消防抖任务 useEffect(() => { return () => onDebounceSearch.cancel(); }, [onDebounceSearch]); return ( <View> <TextInput value={searchText} onChangeText={onChangeSearchText} placeholder="Search" /> </View> ) } export default LodashInputComponent;
方法2:使用useRef保存防抖函数引用
useRef的.current属性不会随组件渲染变化,适合保存防抖函数实例,确保每次调用的都是同一个防抖函数。
import { debounce } from "lodash"; import React, { FC, useState, useRef, useEffect } from "react" import { TextInput, View } from "react-native" interface Props {} const LodashInputComponent: FC<Props> = (props) => { const [searchText, setSearchText] = useState(""); // 用useRef保存防抖函数实例 const debounceRef = useRef<(value: string) => void>(); useEffect(() => { // 初始化防抖函数 debounceRef.current = debounce((value: string) => { console.log("API Send request", value); }, 500); // 卸载时清理防抖任务 return () => debounceRef.current?.cancel(); }, []); const onChangeSearchText = (val: string) => { console.log("Change search text", val); setSearchText(val); // 调用保存的防抖函数 debounceRef.current?.(val); }; return ( <View> <TextInput value={searchText} onChangeText={onChangeSearchText} placeholder="Search" /> </View> ) } export default LodashInputComponent;
预期效果
修改后,输入停止500毫秒后只会触发一次API请求。例如输入"hello world",只会在停止输入后打印一次API Send request hello world,不会每个字符输入都触发请求。
内容的提问来源于stack exchange,提问作者Emre Eke
相关产品推荐
相关产品推荐

