Il y a trois réponses ici, selon la version de React avec laquelle vous (êtes obligé) de travailler et si vous voulez utiliser des hooks.
Tout d'abord:
Il est important de comprendre comment réagissez des œuvres, afin que vous puissiez faire les choses correctement (protip: il est est super valeur en cours d' exécution à travers le React exercice tutoriel sur REACT site Il est bien écrit, et couvre toutes les bases d'une manière qui explique vraiment comment faire. des choses). «Correctement» signifie ici que vous écrivez une interface d'application qui se trouve être rendue dans un navigateur; tout le travail d'interface se produit dans React, pas dans "ce à quoi vous êtes habitué si vous écrivez une page Web" (c'est pourquoi les applications React sont des "applications", pas des "pages Web").
Les applications React sont rendues basées sur deux éléments:
- les propriétés du composant telles que déclarées par le parent qui crée une instance de ce composant, que le parent peut modifier tout au long de son cycle de vie, et
- le propre état interne du composant, qu'il peut modifier lui-même tout au long de son propre cycle de vie.
Ce que vous ne faites expressément pas lorsque vous utilisez React est de générer des éléments HTML, puis de les utiliser: lorsque vous dites à React d'utiliser un <input>
, par exemple, vous ne créez pas d'élément d'entrée HTML, vous dites à React de créer un objet d'entrée React qui se produit pour être rendu en tant qu'élément d'entrée HTML, et dont la gestion des événements regarde, mais n'est pas contrôlée par , les événements d'entrée de l'élément HTML.
Lorsque vous utilisez React, vous générez des éléments d'interface utilisateur de l'application qui présentent à l'utilisateur des données (souvent manipulables), avec l'interaction de l'utilisateur modifiant l'état du composant, ce qui peut entraîner le rendu d'une partie de l'interface de votre application pour refléter le nouvel état. Dans ce modèle, l'état est toujours l'autorité finale, et non «quelle que soit la bibliothèque d'interface utilisateur utilisée pour le rendre», qui sur le Web est le DOM du navigateur. Le DOM est presque une réflexion après coup dans ce modèle de programmation: c'est juste le cadre d'interface utilisateur particulier que React utilise.
Donc, dans le cas d'un élément d'entrée, la logique est:
- Vous saisissez l'élément d'entrée,
- rien n'arrive encore à votre élément d'entrée, l'événement a été intercepté par React et tué immédiatement ,
- React transmet l'événement à la fonction que vous avez configurée pour la gestion des événements,
- cette fonction peut planifier une mise à jour de l'état,
- si c'est le cas, React exécute cette mise à jour d'état (de manière asynchrone!) et déclenchera un
render
appel après la mise à jour, mais uniquement si la mise à jour d'état a changé l'état.
- seulement après que ce rendu a eu lieu, l'interface utilisateur montrera que vous avez "tapé une lettre".
Tout cela se produit en quelques millisecondes, sinon moins, il semble donc que vous ayez tapé dans l'élément d'entrée de la même manière que vous êtes habitué à "utiliser simplement un élément d'entrée sur une page", mais ce n'est absolument pas ce que arrivé.
Cela dit, comment obtenir des valeurs à partir d'éléments dans React:
React 15 et moins, avec ES5
Pour faire les choses correctement, votre composant a une valeur d'état, qui est affichée via un champ d'entrée, et nous pouvons la mettre à jour en faisant que cet élément de l'interface utilisateur renvoie les événements de modification dans le composant:
var Component = React.createClass({
getInitialState: function() {
return {
inputValue: ''
};
},
render: function() {
return (
//...
<input value={this.state.inputValue} onChange={this.updateInputValue}/>
//...
);
},
updateInputValue: function(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
Nous disons donc à React d'utiliser la updateInputValue
fonction pour gérer l'interaction de l'utilisateur, de l'utiliser setState
pour planifier la mise à jour de l'état, et le fait que le fait de puiser render
dans this.state.inputValue
signifie que lorsqu'il réapparaît après la mise à jour de l'état, l'utilisateur verra le texte de mise à jour en fonction de ce qu'il a tapé.
addendum basé sur les commentaires
Étant donné que les entrées de l'interface utilisateur représentent des valeurs d'état (considérez ce qui se passe si un utilisateur ferme son onglet à mi-chemin et que l'onglet est restauré. Toutes les valeurs qu'il a renseignées doivent-elles être restaurées? Si tel est le cas, c'est l'état). Cela peut vous donner l'impression qu'un grand formulaire nécessite des dizaines, voire une centaine de formulaires de saisie, mais React consiste à modéliser votre interface utilisateur de manière maintenable: vous n'avez pas 100 champs de saisie indépendants, vous avez des groupes d'entrées associées, vous capturez donc chaque group dans un composant, puis construisez votre formulaire "maître" sous la forme d'un ensemble de groupes.
MyForm:
render:
<PersonalData/>
<AppPreferences/>
<ThirdParty/>
...
C'est également beaucoup plus facile à entretenir qu'un composant de formulaire unique géant. Divisez les groupes en composants avec maintenance de l'état, où chaque composant est uniquement responsable du suivi de quelques champs d'entrée à la fois.
Vous pouvez également avoir l'impression que c'est "un tracas" d'écrire tout ce code, mais c'est une fausse économie: les développeurs-qui-ne-sont-pas-vous, y compris le futur vous, bénéficient en fait grandement de voir toutes ces entrées connectées explicitement, car cela rend les chemins de code beaucoup plus faciles à tracer. Cependant, vous pouvez toujours optimiser. Par exemple, vous pouvez écrire un éditeur de liens d'état
MyComponent = React.createClass({
getInitialState() {
return {
firstName: this.props.firstName || "",
lastName: this.props.lastName || ""
...: ...
...
}
},
componentWillMount() {
Object.keys(this.state).forEach(n => {
let fn = n + 'Changed';
this[fn] = evt => {
let update = {};
update[n] = evt.target.value;
this.setState(update);
});
});
},
render: function() {
return Object.keys(this.state).map(n => {
<input
key={n}
type="text"
value={this.state[n]}
onChange={this[n + 'Changed']}/>
});
}
});
Bien sûr, il existe des versions améliorées de ceci, alors rendez-vous sur https://npmjs.com et recherchez une solution de liaison d'état React que vous préférez. L'Open Source consiste principalement à trouver ce que les autres ont déjà fait et à l'utiliser au lieu de tout écrire vous-même à partir de zéro.
React 16 (et 15.5 transitionnel) et JS `` moderne ''
Depuis React 16 (et le démarrage progressif avec 15.5), l' createClass
appel n'est plus pris en charge et la syntaxe de classe doit être utilisée. Cela change deux choses: la syntaxe de classe évidente, mais aussi la this
liaison de contexte qui createClass
peut faire "gratuitement", donc pour vous assurer que tout fonctionne toujours, assurez-vous que vous utilisez la notation "grosse flèche" pour this
préserver le contexte des fonctions anonymes dans les onWhatever
gestionnaires, telles que le que onChange
nous utilisons dans le code ici:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
};
}
render() {
return (
//...
<input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
//...
);
},
updateInputValue(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
Vous avez peut-être également vu des gens utiliser bind
dans leur constructeur pour toutes leurs fonctions de gestion d'événements, comme ceci:
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
...
}
render() {
return (
...
<element onclick={this.handler}/>
...
);
}
Ne fais pas ça.
Presque chaque fois que vous l'utilisez bind
, le proverbial «vous vous trompez» s'applique. Votre classe définit déjà le prototype d'objet et définit donc déjà le contexte de l'instance. Ne mettez pas bind
de dessus; utilisez le transfert d'événement normal au lieu de dupliquer tous vos appels de fonction dans le constructeur, car cette duplication augmente votre surface de bogue et rend beaucoup plus difficile le suivi des erreurs car le problème peut être dans votre constructeur au lieu de l'endroit où vous appelez votre code. En plus d'imposer un fardeau de maintenance à d'autres personnes avec lesquelles vous (avez ou choisissez) de travailler.
Oui, je sais que les documents de réaction disent que ça va. Ce n'est pas, ne le fais pas.
React 16.8, en utilisant des composants de fonction avec des crochets
Depuis React 16.8, le composant de fonction (c'est-à-dire littéralement juste une fonction qui en prend props
comme argument peut être utilisée comme s'il s'agissait d'une instance d'une classe de composant, sans jamais écrire de classe) peut également recevoir un état, grâce à l'utilisation de hooks .
Si vous n'avez pas besoin d'un code de classe complet et qu'une seule fonction d'instance fera l'affaire, vous pouvez maintenant utiliser le useState
hook pour obtenir une seule variable d'état et sa fonction de mise à jour, qui fonctionne à peu près de la même manière que les exemples ci-dessus, sauf sans l' setState
appel de fonction:
import { useState } from 'react';
function myFunctionalComponentFunction() {
const [input, setInput] = useState(''); // '' is the initial state value
return (
<div>
<label>Please specify:</label>
<input value={input} onInput={e => setInput(e.target.value)}/>
</div>
);
}
Auparavant, la distinction non officielle entre les classes et les composants de fonction était "les composants de fonction n'ont pas d'état", nous ne pouvons donc plus nous cacher derrière celui-là: la différence entre les composants de fonction et les composants de classes peut être trouvée répartie sur plusieurs pages dans le très bien -documentation de réaction écrite (pas de raccourci une explication de ligne pour mal interpréter pour vous!) que vous devriez lire afin que vous sachiez ce que vous faites et que vous puissiez ainsi savoir si vous avez choisi la meilleure solution (quoi que cela signifie pour vous) pour vous programmer d'un problème que vous rencontrez.
this.onSubmit.bind(this);