自定义Slider组件问题:添加onValueChange后滑块手柄无法拖动
问题原因
你的自定义Slider组件中,在SliderPrimitive.Root上先设置了内部的onValueChange={handleChange},随后又展开了...props。当父组件(Price组件)传递onValueChange回调时,props中的这个回调会覆盖掉你定义的内部handleChange,导致:
- 内部的
value状态无法更新,滑块手柄的位置依赖这个状态,所以看起来没动 - 父组件的
searchByPrice状态会被更新,因此控制台能看到值变更
解决方案
修改Slider组件的逻辑,将父组件传递的onValueChange回调单独提取,并在内部状态更新后调用它,同时避免props覆盖内部的事件处理函数。
修改后的Slider组件代码:
"use client" import * as React from "react" import * as SliderPrimitive from "@radix-ui/react-slider" import { cn } from "@/lib/utils" const Slider = React.forwardRef(({ className, defaultValue = [0, 1000], max = 1000, step = 1, onValueChange: externalOnValueChange, // 单独提取父组件的回调 ...props }, ref) => { const [value, setValue] = React.useState(defaultValue); const handleChange = (newValue) => { // 先更新内部状态,保证UI同步 setValue(newValue); // 调用父组件传递的回调 if (externalOnValueChange) { externalOnValueChange(newValue); } }; const shouldDisplayRangeTogether = value[1] - value[0] < 100; return ( <div className="relative w-full"> <SliderPrimitive.Root ref={ref} className={cn("relative flex w-full touch-none select-none items-center", className)} value={value} onValueChange={handleChange} max={max} step={step} {...props}> {/* props中已无onValueChange,不会覆盖内部处理函数 */} <SliderPrimitive.Track className="relative h-0.5 w-full grow overflow-hidden rounded-full bg-gray-200 dark:bg-slate-800"> <SliderPrimitive.Range className="absolute h-full bg-dark-gray dark:bg-slate-50" /> </SliderPrimitive.Track> {value.map((val, index) => ( <React.Fragment key={index}> <SliderPrimitive.Thumb className="block h-3 w-3 rounded-full border border-dark-gray bg-white duration-700 hover:bg-green ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-slate-950 focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 dark:border-slate-50 dark:bg-slate-950 dark:focus-visible:ring-slate-300" /> {!shouldDisplayRangeTogether && ( <div className="absolute -top-8 w-10 text-center text-sm font-medium transform -translate-x-1/2" style={{ left: `${(val / max) * 95}%` }} > {props.currency}{val} </div> )} </React.Fragment> ))} </SliderPrimitive.Root> {shouldDisplayRangeTogether && ( <div className="absolute -top-8 left-1/2 transform -translate-x-1/2 text-sm font-semibold" > {props.currency}{value[0]} - {props.currency}{value[1]} </div> )} </div> ); }); Slider.displayName = SliderPrimitive.Root.displayName; export { Slider }
说明
- 单独提取父组件的
onValueChange并命名为externalOnValueChange,避免展开props时覆盖内部的事件处理 - 在
handleChange中先更新内部value状态,确保滑块手柄的位置能实时同步,再调用父组件的回调传递最新值 - 父组件(Price组件)的使用方式不需要修改,保持原样即可
内容的提问来源于stack exchange,提问作者Ahmed Faraz
相关产品推荐
相关产品推荐

