Material UI+TS受控输入onChange防抖函数失效,返回固定值求助
问题原因分析
你的问题根源有两个核心点:
- React合成事件的池化机制:React的合成事件对象(比如
e)会在回调执行后被回收复用,防抖函数延迟1秒执行时,原事件对象的target.value已经被重置,导致拿到固定不变的值。 - 防抖函数未正确持久化:组件每次渲染时,
handleChange都会重新创建新的函数实例,如果防抖函数没有绑定到稳定的函数引用上,会导致每次触发都生成新的防抖逻辑,或者捕获旧的状态/函数引用。
解决方案
方案1:提前提取事件值(推荐)
直接在onChange中提取value,再传递给防抖函数,规避合成事件池化的影响:
修改Input组件
<TextField type="color" value={hex} onChange={e => { const inputValue = e.target.value; handleChangeOpt(inputValue, 'hex'); }} />
更新处理函数参数
把原handleChange的第一个参数从事件对象改为直接接收value:
const handleChange = (value: string, colorType: string) => { if(colorType === 'hex'){ if(value !== ""){ convertCode(value); } console.log(hex); } else if (colorType === 'rgb') { const rgb_split_data = splitRGB(value); setR(rgb_split_data.r); setG(rgb_split_data.g); setB(rgb_split_data.b); setRGBASlider(50); } else if (colorType === 'hsl') { const hsl_hex = HSLToHex(value); const hsl_rgb = HSLToRGB(value); const hsl_rgb_split = splitRGB(hsl_rgb); setHsl(value); setHex(hsl_hex); setR(hsl_rgb_split.r); setG(hsl_rgb_split.g); setB(hsl_rgb_split.b); setRGBASlider(50); } };
持久化防抖函数
使用use-debounce库的useDebouncedCallback,同时用useCallback确保handleChange的引用稳定:
import { useCallback } from 'react'; import { useDebouncedCallback } from 'use-debounce'; // 用useCallback稳定handleChange的引用 const handleChange = useCallback((value: string, colorType: string) => { // 上述更新后的逻辑 }, [convertCode, splitRGB, HSLToHex, HSLToRGB, setR, setG, setB, setHex, setHsl, setRGBASlider]); // 创建防抖函数 const handleChangeOpt = useDebouncedCallback(handleChange, 1000);
方案2:保留事件对象的写法
如果必须使用事件对象,调用e.persist()阻止React回收事件对象,同时确保防抖函数引用稳定:
修改Input组件
<TextField type="color" value={hex} onChange={e => { e.persist(); // 保留事件对象,避免被回收 handleChangeOpt(e, 'hex'); }} />
持久化防抖函数
用useMemo包裹防抖函数,依赖稳定的handleChange引用:
import { useCallback, useMemo } from 'react'; import debounce from '@merry-solutions/debounce'; // 或其他防抖库 // 稳定handleChange引用 const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, colorType: string) => { // 原逻辑 }, [convertCode, splitRGB, HSLToHex, HSLToRGB, setR, setG, setB, setHex, setHsl, setRGBASlider]); // 用useMemo创建持久化的防抖函数 const handleChangeOpt = useMemo(() => debounce(handleChange, 1000), [handleChange]);
内容的提问来源于stack exchange,提问作者Vishal Arpit Kumar
相关产品推荐
相关产品推荐

