web-dev-qa-db-fra.com

Le curseur de saisie HTML5 JSX React ne fonctionne pas

J'utilise React.JS pour une construction et je construis un curseur d'entrée de plage avec deux choix pour un composant.

c'est mon code:

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

Lorsque je le place dans mon composant de rendu côté client et que je tente de l'activer, il ne bouge pas du tout. En le testant sur une version JS/PHP en cours, cela fonctionne bien.

Pourquoi cela ne fonctionne-t-il pas dans JSX/React.JS et quel serait le travail suggéré?

Merci!

11
CodeFromthe510

Les interactions utilisateur n’ont aucun effet car un <input> avec value prop est considéré comme contrôlé. Cela signifie que la valeur affichée est entièrement contrôlée par la fonction render. Donc, pour mettre à jour la valeur d'entrée, vous devez utiliser l'événement onChange. Exemple:

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"/>
  );
}

Vous pouvez également utiliser defaultValue au lieu de value. Dans ce cas, <input> est considéré comme uncontrolled et toutes les interactions utilisateur sont immédiatement reflétées par l'élément lui-même sans appeler la fonction render de votre composant.

Plus d'informations à ce sujet dans les documents officiels documentation

28
xCrZx

Je pense que les réponses précédentes résolvent votre problème. Cependant, je dirais que la solution n'a pas besoin d'impliquer les états de réaction.

La seule raison derrière votre curseur d’entrée gelée est que vous avez codé en dur sa valeur à 3, comme le suggère @Colin Whitmarsh.

Cela fonctionne simplement:

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

Maintenant, vous avez probablement besoin de sa sortie pour faire quelque chose. Vous pouvez utiliser onChange={this.handleChange} comme @xCrZx dans sa réponse. Mais dans handleChange vous ne devez pas nécessairement mettre à jour votre état. En fonction de votre logique, vous pouvez éviter d'augmenter la complexité de votre état et simplement coder votre logique dans handleChange.

Si vous évitez de mettre à jour l'état, vous économiserez probablement des rendus et vos performances s'amélioreront.

3
Daniel Reina

Voici une solution pour créer plusieurs curseurs ou même un seul curseur avec le gestionnaire d'événements transmis Nous pouvons simplement utiliser une entrée HTML de type Range rc-slider et react-input-range ne pas envoyer gestionnaire d'événementsonChange ou onAfterChange ils envoient la valeur du curseur implicitement, nous ne pouvons donc pas gérer la forme des curseurs ni les créer à la volée. 

jsfiddle snippet

Pour plus nous pouvons vérifier HTML input Range et CSS fourni par CSS-Tricks

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>

Cette solution fonctionne parfaitement avec moi;)

Utiliser CodeSandbox

0
Abdallah Okasha

Essaye ça:

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

Je suggère de changer value = "3" en defaultValue = "3" , sinon je pense que la valeur est codée en dur en "3" et peut être difficile voire impossible à modifier. La fonction onInput recherche la valeur et l'ajoute à l'état afin que les données puissent être transmises à un autre composant ou une autre fonction. Il existe probablement une solution plus élégante à votre problème, mais ce qui précède devrait fonctionner. 

0
Colin Whitmarsh