React.js灯光亮度滑块卡顿问题及平滑移动需求
解决React滑块拖动卡顿问题
问题根源
当前代码中,滑块的onChange事件直接触发lightOn函数,该函数会同步发起POST请求+GET请求,拖动滑块时每移动一次就触发一轮网络请求,大量异步请求阻塞主线程,导致UI冻结卡顿。
修复方案
- 分离本地状态更新与网络请求:拖动滑块时仅更新本地状态,松开滑块后再向服务器发送请求
- 移除子组件冗余状态:子组件无需维护全量设备列表
light,复用父组件传递的属性或本地状态即可 - 避免全量设备查询:更新亮度后无需重新拉取所有设备,直接通过父组件同步状态即可
修改后的代码
DiscoverOffice.js
const DiscoverOffice = () => { const [light, setLight] = useState([]); const getDevices = async() => { try { const result = await axios.get('xxx.com', { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${cookies.get('accesstoken')}` }, }); setLight(result.data.attributes.light); } catch (err) { console.log(err); } } useEffect(() => { getDevices(); }, []); // 子组件调用该方法更新单设备亮度,无需拉取全量数据 const updateLightBrightness = (entityId, newBrightness) => { setLight(prev => prev.map(item => item.entity_id === entityId ? {...item, brightness: newBrightness} : item )); } return ( <> {light.map((item) => <LightSliderBar key={item.entity_id} item={item} updateBrightness={updateLightBrightness} /> )} </> ); } export default DiscoverOffice;
LightSliderBar.js
import { useState, useCallback } from 'react'; const LightSliderBar = ({ item, updateBrightness }) => { const cookies = new Cookies(); const entity_id = item.entity_id; const [brightness_value, setBrightnessValue] = useState(item.brightness); // 向服务器同步亮度值 const syncBrightnessToServer = useCallback(async () => { try { await axios.post('xxx.com', { entity_id: entity_id, brightness: brightness_value }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${cookies.get('accesstoken')}` }, }); // 通知父组件更新状态 updateBrightness(entity_id, brightness_value); console.log('亮度更新成功'); } catch (err) { console.log('亮度更新失败:', err); // 失败时回退到初始值 setBrightnessValue(item.brightness); } }, [entity_id, brightness_value, cookies, updateBrightness, item.brightness]); // 拖动时仅更新本地状态 const handleSliderChange = useCallback((e) => { setBrightnessValue(Number(e.target.value)); }, []); return ( <div> <input className="range-input" type="range" name="speed" min="0" max="100" id="slider" value={brightness_value} onChange={handleSliderChange} onMouseUp={syncBrightnessToServer} onTouchEnd={syncBrightnessToServer} // 适配移动端触摸操作 style={{ background: gradient, }} /> </div> ); }; // 用React.memo避免父组件重渲染时子组件不必要刷新 export default React.memo(LightSliderBar);
额外优化建议
- 若需要更严谨的请求控制,可对
syncBrightnessToServer添加防抖处理,避免快速拖动松开后重复发送请求:
import { debounce } from 'lodash'; // 定义防抖后的请求函数 const debouncedSync = useCallback(debounce(syncBrightnessToServer, 300), [syncBrightnessToServer]); // 替换onMouseUp/onTouchEnd的调用为debouncedSync
内容的提问来源于stack exchange,提问作者user20271619
相关产品推荐
相关产品推荐

