React中useEffect传入的State参数在轮询时未读取问题
问题解决:加密货币应用中防抖/轮询无法读取最新State值
核心问题原因
闭包导致定时器和防抖函数捕获的是组件初始渲染时的State值,后续State更新后,旧的函数引用依然持有旧值,最终引发轮询时参数为undefined的问题。
修复步骤
1. 让API调用函数直接读取最新State(推荐方案)
将handleInitPoll改为直接读取组件内的State,而非通过参数传递,彻底避免闭包捕获旧值:
const handleInitPoll = useCallback(() => { getSwapPrice(pair, transactionType, fromCurrencyAmount || 0) .then((res) => { if (!res.price) { setIsLoading(true); } else if (res.error) { setErrorMessage(res.error); } else if (res.price) { setIsLoading(false); setSwapPriceInfo(res); } }); }, [pair, transactionType, fromCurrencyAmount]); // State变化时自动更新函数引用
2. 修复useEffect中的轮询逻辑
移除setInterval的参数传递,直接调用更新后的handleInitPoll,同时确保每次State变化时清除旧定时器并创建新实例:
useEffect(() => { // 初始立即调用一次 handleInitPoll(); // 轮询调用最新的handleInitPoll const timer = setInterval(handleInitPoll, 6000); // 组件卸载或依赖变化时清除定时器 return () => clearInterval(timer); }, [handleInitPoll]); // 依赖改为更新后的函数引用
3. 修复防抖函数的闭包问题
用useCallback包裹防抖函数,确保依赖变化时重新创建防抖实例,调用时无需额外传参:
// 创建防抖函数,依赖handleInitPoll保证引用最新 const debounceOnChange = useCallback(debounce(() => { handleInitPoll(); }, 500), [handleInitPoll]); // 输入变更时直接调用防抖函数 const handleAssetAmount = (e) => { const { value } = e.target; const formattedAmount = handleAssetAmountFormat(value); setFromCurrencyAmount(formattedAmount); validateInputAmount(formattedAmount); debounceOnChange(); };
替代方案(需保留参数传递时使用)
如果业务必须通过参数传递值,需确保定时器和防抖函数始终获取最新State:
- 轮询部分:在定时器回调中直接读取当前State,而非初始参数
useEffect(() => { handleInitPoll(pair, transactionType, fromCurrencyAmount); const timer = setInterval(() => { // 每次调用时读取最新的State值 handleInitPoll(pair, transactionType, fromCurrencyAmount); }, 6000); return () => clearInterval(timer); }, [pair, transactionType, fromCurrencyAmount]); - 防抖部分:在
useCallback中加入正确依赖,确保防抖函数随State更新const debounceOnChange = useCallback( debounce((p, t, v) => handleInitPoll(p, t, v), 500), [handleInitPoll] );
内容的提问来源于stack exchange,提问作者Kimbo
相关产品推荐
相关产品推荐

