React.JSをビルドに使用しており、コンポーネントに2つの選択肢がある範囲入力スライダーを構築しています。
これは私のコードです:
<input id="typeinp" type="range" min="0" max="5" value="3" step="1"/>
クライアント側のレンダリングコンポーネントに配置して切り替えようとすると、まったく動きません。私が行っているJS/PHPビルドでテストすると、うまくいきます。
JSX/React.JSでこれが機能しないのはなぜですか?また、推奨される回避策は何ですか?
ありがとう!
<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
関数を呼び出さずに要素自体に即座に反映されます。
詳細については、公式 ドキュメント
以前の回答で問題は解決すると思います。ただし、ソリューションにReact状態を含める必要はありません。
フリーズされた入力スライダーの背後にある唯一の理由は、@ Colin Whitmarshが示唆するように、その値を3にハードコーディングしたことです。
単純に、これは機能します:
<input id="typeinp" type="range" min="0" max="5" defaultValue="3" step="1"/>
今、あなたはおそらく何かをするためにその出力が必要です。彼の答えで@xCrZxの状態としてonChange={this.handleChange}
を使用できます。ただし、handleChange
内では、必ずしも状態を更新する必要はありません。ロジックに応じて、状態の複雑さを増すことを避け、ロジックをhandleChange
内に単純にコーディングできます。
状態の更新を避けると、おそらくいくつかのレンダリングを保存し、パフォーマンスが向上します。
これを試して:
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関数は値を検出し、それを状態に追加して、データを別のコンポーネントまたは関数に渡すことができるようにします。問題に対するよりエレガントな解決策がある可能性がありますが、上記の方法でうまくいくはずです。
これは、複数のスライダーまたはイベントハンドラーが渡された単一のスライダーのフォームを作成するためのソリューションです。範囲 rc-slider および react-input-range のHTML入力を使用できます。送信しないイベントハンドラーonChange
またはonAfterChange
スライダーの値を暗黙的に送信するため、処理できませんスライダーの形またはそれらをその場で作成します。
詳細については、 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 の使用