web-dev-qa-db-ja.com

JSX React HTML5入力スライダーが機能しない

React.JSをビルドに使用しており、コンポーネントに2つの選択肢がある範囲入力スライダーを構築しています。

これは私のコードです:

<input id="typeinp" type="range" min="0" max="5" value="3" step="1"/>

クライアント側のレンダリングコンポーネントに配置して切り替えようとすると、まったく動きません。私が行っているJS/PHPビルドでテストすると、うまくいきます。

JSX/React.JSでこれが機能しないのはなぜですか?また、推奨される回避策は何ですか?

ありがとう!

16
CodeFromthe510

<input> with value propは、controlledと見なされます。これは、表示される値がrender関数によって完全に制御されることを意味します。したがって、入力値を実際に更新するには、onChangeイベントを使用する必要があります。例:

getInitialState: function() {
  return {value: 3};
},
handleChange: function(event) {
  this.setState({value: event.target.value});
},
render: function() {
  return (
    <input 
      id="typeinp" 
      type="range" 
      min="0" max="5" 
      value={this.state.value} 
      onChange={this.handleChange}
      step="1"/>
  );
}

defaultValueの代わりにvalueを使用することもできます。この場合 <input>uncontrolledと見なされ、ユーザーの操作はすべて、コンポーネントのrender関数を呼び出さずに要素自体に即座に反映されます。

詳細については、公式 ドキュメント

36
xCrZx

以前の回答で問題は解決すると思います。ただし、ソリューションにReact状態を含める必要はありません。

フリーズされた入力スライダーの背後にある唯一の理由は、@ Colin Whitmarshが示唆するように、その値を3にハードコーディングしたことです。

単純に、これは機能します:

<input id="typeinp" type="range" min="0" max="5" defaultValue="3" step="1"/>

今、あなたはおそらく何かをするためにその出力が必要です。彼の答えで@xCrZxの状態としてonChange={this.handleChange}を使用できます。ただし、handleChange内では、必ずしも状態を更新する必要はありません。ロジックに応じて、状態の複雑さを増すことを避け、ロジックをhandleChange内に単純にコーディングできます。

状態の更新を避けると、おそらくいくつかのレンダリングを保存し、パフォーマンスが向上します。

3
Daniel Reina

これを試して:

onInput() {
    var input = document.getElementById("typeinp");
    var currentVal = input.value;
    this.setState({
      value: currentVal
    })
}

<input id="typeinp" type="range" min="0" max="5" step="1" defaultValue="3" onInput={this.onInput.bind(this)}/>

Value = "3"をdefaultValue = "3"に変更することをお勧めします。そうしないと、値が "3"にハードコードされ、変更が困難または不可能になると思います。 onInput関数は値を検出し、それを状態に追加して、データを別のコンポーネントまたは関数に渡すことができるようにします。問題に対するよりエレガントな解決策がある可能性がありますが、上記の方法でうまくいくはずです。

2
Colin Whitmarsh

これは、複数のスライダーまたはイベントハンドラーが渡された単一のスライダーのフォームを作成するためのソリューションです。範囲 rc-slider および react-input-range のHTML入力を使用できます。送信しないイベントハンドラーonChangeまたはonAfterChangeスライダーの値を暗黙的に送信するため、処理できませんスライダーの形またはそれらをその場で作成します。

jsfiddleスニペット

詳細については、 HTML入力範囲 および CSS-Tricks によって提供されるCSSを確認できます。

class SlidersExample extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      slidersLabels: ["A", "B", "C", "D"],
      sumOfCustomWeights: 0,
      slidersWeights: []
    };
  }
  componentDidMount() {
    const slidersLabels = this.state.slidersLabels;
    const slidersWeights = [];
    for (var i = 0; i < slidersLabels.length; ++i)
      slidersWeights[slidersLabels[i]] = 0;
    this.setState({ slidersWeights });
  }

  render() {
    return (
      <div>
        {this.generateSliders()}
        <span> Total Weights: {this.state.sumOfCustomWeights} </span>
      </div>
    );
  }
  generateSliders() {
    const slidersLabels = this.state.slidersLabels;
    var sliders = [];
    for (var i = 0; i < slidersLabels.length; ++i) {
      sliders.Push(
        <div style={{ marginTop: "20px", marginBottom: "20px" }}>
          <span style={{ fontSize: "16px", marginBottom: "6px" }}>
            {" "}
            {slidersLabels[i]} ({this.state.slidersWeights[slidersLabels[i]]})%
          </span>
          <input
            id={slidersLabels[i]}
            type="range"
            defaultValue="0"
            min="0"
            max="100"
            className="slider"
            onChange={this.handleSliderChange.bind(this)}
            step="1"
          />
        </div>
      );
    }
     return sliders;
  }
  handleSliderChange(event) {
    //console.log(event.target.value, " ", event.target.id);
    var id = event.target.id;
    var value = event.target.value;
    const slidersWeights = this.state.slidersWeights;
    slidersWeights[id] = parseInt(value);
    var sumOfCustomWeights = 0;
    const slidersLabels = this.state.slidersLabels;
    for (var i = 0; i < slidersLabels.length; i++)
      sumOfCustomWeights += slidersWeights[slidersLabels[i]];
    this.setState({ slidersWeights, sumOfCustomWeights });
  }
}

ReactDOM.render(<SlidersExample />, document.querySelector("#app"));
input[type=range] {
  -webkit-appearance: none;
  margin: 18px 0;
  width: 100%;
}
input[type=range]:focus {
  outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
  width: 100%;
  height: 8.4px;
  cursor: pointer;
  animate: 0.2s;
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
  background: #3071a9;
  border-radius: 1.3px;
  border: 0.2px solid #010101;
}
input[type=range]::-webkit-slider-thumb {
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
  border: 1px solid #000000;
  height: 36px;
  width: 16px;
  border-radius: 3px;
  background: #ffffff;
  cursor: pointer;
  -webkit-appearance: none;
  margin-top: -14px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
  background: #367ebd;
}
input[type=range]::-moz-range-track {
  width: 100%;
  height: 8.4px;
  cursor: pointer;
  animate: 0.2s;
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
  background: #3071a9;
  border-radius: 1.3px;
  border: 0.2px solid #010101;
}
input[type=range]::-moz-range-thumb {
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
  border: 1px solid #000000;
  height: 36px;
  width: 16px;
  border-radius: 3px;
  background: #ffffff;
  cursor: pointer;
}
input[type=range]::-ms-track {
  width: 100%;
  height: 8.4px;
  cursor: pointer;
  animate: 0.2s;
  background: transparent;
  border-color: transparent;
  border-width: 16px 0;
  color: transparent;
}
input[type=range]::-ms-fill-lower {
  background: #2a6495;
  border: 0.2px solid #010101;
  border-radius: 2.6px;
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
  background: #3071a9;
  border: 0.2px solid #010101;
  border-radius: 2.6px;
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]::-ms-thumb {
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
  border: 1px solid #000000;
  height: 36px;
  width: 16px;
  border-radius: 3px;
  background: #ffffff;
  cursor: pointer;
}
input[type=range]:focus::-ms-fill-lower {
  background: #3071a9;
}
input[type=range]:focus::-ms-fill-upper {
  background: #367ebd;
}

#app{
  margin-right: 100px;
  margin-left: 100px;
  margin-bottom: 100px;
  }
<!DOCTYPE html>
<html>
<body>


<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"> </div>
</body>
</html>

このソリューションは私と完璧に連携しています;)

CodeSandbox の使用

1
Abdallah Okasha