我正在尝试使用 React 钩子制作一个基本的输入范围滑块组件。 但是,滑动实际值旋钮不起作用。 只有直接单击幻灯片轨道上的新值位置即可更改值。
示例代码笔: https://codepen.io/rmichels/pen/WNegjyK
这是我当前的组件代码,上面的代码笔复制了它:
import React, { useState } from "react";
const useSlider = (min, max, defaultState, label, id) => {
const [state, setSlide] = useState(defaultState);
const handleChange = e => {
setSlide(e.target.value);
};
const Slider = () => (
<input
type="range"
id={id}
min={min}
max={max}
step={10}
value={state}
onChange={handleChange}
/>
);
return [state, Slider, setSlide];
};
export default useSlider;
我想单击旋钮并将其左右滑动,触发onChange
函数并在更改值时触发setState
值。
组件在滑块的每次更新时设置状态,因此组件将重新呈现,并且您失去焦点或对滑块手柄的按住。相反,应在与句柄的交互完成时更新状态。
//import { useState } from 'react';
const { useState } = React;
const useSlider = (min, max, defaultState, label, id) => {
const [state, setSlide] = useState(defaultState);
const handleChange = e => {
console.log('setting level', e.target.value)
setSlide(e.target.value);
};
const Slider = () => (
<input
type="range"
id={id}
min={min}
max={max}
step={0.5}
// value={state} // don't set value from state
defaultValue={state} // but instead pass state value as default value
onChange={e => console.log(e.target.value)} // don't set state on all change as react will re-render
onMouseUp={handleChange} // only set state when handle is released
/>
);
return [state, Slider, setSlide];
};
const App = () => {
const [slideValue, Slider] = useSlider(
1,
100,
70,
"Threshold",
"threshold"
);
return (
<div>
<Slider />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('app'))
每次调用此钩子时,您都会定义一个全新的 Slider 功能组件。首次呈现应用程序时,您渲染滑块版本 1.0。第二次,渲染滑块版本 2.0。它们可能具有非常相似的代码,但它们是不同的组件,因此 react 卸载旧组件并挂载新组件。因此,旧的输入从 dom 中删除,新的输入被放在它的位置,你不再拖动任何东西。
钩子不适合动态创建组件。您可以通过记住滑块组件来改善这一点,但是一旦您因任何原因必须中断记忆,就必须定义一个全新的组件,并且此问题或类似问题将再次出现。
相反,我建议 useSlider 返回 props,然后让调用者将它们放在标准的input
组件上。由于组件始终属于同一类型,因此将不再卸载和重新装载。
const useSlider = (min, max, defaultState, label, id) => {
const [state, setSlide] = useState(defaultState);
const handleChange = e => {
console.log('setting level', e.target.value)
setSlide(e.target.value);
}
const props = {
type: 'range',
id,
min,
max,
step: 0.5,
value: state,
onChange: handleChange
}
return props
}
const App = () => {
const sliderProps = useSlider(1, 100, 70, "Threshold", 'threshold');
return (
<div>
<input {...sliderProps}/>
</div>
)
};