输入范围滑块,因为反作用钩不滑动

时间:2019-09-17 04:57:26

标签: reactjs slider react-hooks

我正在尝试使用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

2 个答案:

答案 0 :(得分:0)

您的组件在每次更新滑块时都处于设置状态,因此该组件正在重新渲染,并且您失去焦点或握住滑块手柄。相反,您应该在与手柄的交互完成后更新状态。

//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'))

答案 1 :(得分:0)

每次调用此挂钩时,您都定义一个全新的Slider功能组件。 App首次渲染时,将渲染Slider 1.0版本。第二次,您呈现一个Slider 2.0版。它们可能具有非常相似的代码,但是它们是不同的组件,因此,react会卸载旧的组件并安装新的组件。因此,从dom中删除了旧输入,并在其中放置了新输入,您再也无需拖移任何东西。

钩子不利于动态创建组件。您可以通过记忆滑块组件来对此有所改善,但是一旦由于任何原因不得不中断记忆,就必须定义一个全新的组件,并且这个问题或类似的问题将会再次出现。

相反,我建议useSlider返回道具,然后让调用者将它们放在标准的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>
  )
};