web-dev-qa-db-fra.com

Comment modifier plusieurs composants contrôlés par l'entrée dans React?

J'ai un composant qui stocke un objet de contact comme état - {prénom: "John", nom: "biche", téléphone: "1234567890} je veux créer un formulaire pour éditer cet objet mais si je veux que les entrées contiennent la valeur Pour le paramètre contact d'origine, il faut que chaque entrée soit contrôlée, mais je ne sais pas comment créer une fonction handleChange qui sera ajustée à chaque paramètre car mon état ne contient que {contact: {...}}. Voici ce que j'ai actuellement -

  getInitialState: function () {
    return ({contact: {}});
  },
  handleChange: function (event) {
    this.setState({contact: event.target.value });
  },
  render: function () {
    return (
        <div>
          <input type="text" onChange={this.handleChange} value={this.state.contact.firstName}/>
          <input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
          <input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
        </div>
      );
    }

Je souhaite dans ma poignéeChange je peux faire quelque chose comme

  handleChange: function (event) {
    this.setState({contact.firstName: event.target.value });
  }
25
akantoword

Il existe un moyen "simple" de le faire et un moyen "intelligent". Si vous me le demandez, faire les choses intelligemment n’est pas toujours le meilleur choix, car je pourrais avoir plus de difficulté à travailler plus tard. Dans ce cas, les deux sont très compréhensibles.

Note latérale: Je voudrais vous demander une chose à savoir: devez-vous mettre à jour l'objet contact ou pouvez-vous simplement garder firstName etc. directement sur l'état? Peut-être que vous avez beaucoup de données dans l'état du composant? Si tel est le cas, c'est probablement une bonne idée de le séparer en composants plus petits avec des responsabilités plus étroites.

La manière "simple"

  changeFirstName: function (event) {
    const contact = this.state.contact;
    contact.firstName = event.target.value;
    this.setState({ contact: contact });
  },
  changeLastName: function (event) {
    const contact = this.state.contact;
    contact.lastName = event.target.value;
    this.setState({ contact: contact });
  },
  changePhone: function (event) {
    const contact = this.state.contact;
    contact.phone = event.target.value;
    this.setState({ contact: contact });
  },
  render: function () {
    return (
      <div>
        <input type="text" onChange={this.changeFirstName.bind(this)} value={this.state.contact.firstName}/>
        <input type="text" onChange={this.changeLastName.bind(this)} value={this.state.contact.lastName}/>
        <input type="text" onChange={this.changePhone.bind(this)} value={this.state.contact.phone}/>
      </div>
    );
  }

La façon "intelligente"

  handleChange: function (propertyName, event) {
    const contact = this.state.contact;
    contact[propertyName] = event.target.value;
    this.setState({ contact: contact });
  },
  render: function () {
    return (
      <div>
        <input type="text" onChange={this.handleChange.bind(this, 'firstName')} value={this.state.contact.firstName}/>
        <input type="text" onChange={this.handleChange.bind(this, 'lastName')} value={this.state.contact.lastName}/>
        <input type="text" onChange={this.handleChange.bind(this, 'phone')} value={this.state.contact.lastName}/>
      </div>
    );
  }



Mise à jour: mêmes exemples avec ES2015 +

Cette section contient les mêmes exemples que ceux illustrés ci-dessus, mais en utilisant les fonctionnalités de ES2015 +.

Pour prendre en charge les fonctionnalités suivantes sur tous les navigateurs, vous devez transpiler votre code avec Babel en utilisant par exemple Les préréglages es2015 et réactifs , .__ et le plugin. stage-0 .

Vous trouverez ci-dessous des exemples mis à jour, en utilisant destructuring d'objet pour obtenir le contact de l'état, opérateur de propagation en Créer un objet contact mis à jour au lieu de le transformer , créer des composants comme Classes par étendre React.Component , et utiliser fonctions de flèche pour créer des rappels afin que nous ne puissions pas Je n'ai pas à bind(this).

La manière "simple", ES2015 +

class ContactEdit extends React.Component {

  changeFirstName = (event) => {
    const { contact } = this.state;
    const newContact = {
      ...contact,
      firstName: event.target.value
    };
    this.setState({ contact: newContact });
  }
  changeLastName = (event) => {
    const { contact } = this.state;
    const newContact = {
      ...contact,
      lastName: event.target.value
    };
    this.setState({ contact: newContact });
  }
  changePhone = (event) => {
    const { contact } = this.state;
    const newContact = {
      ...contact,
      phone: event.target.value
    };
    this.setState({ contact: newContact });
  }

  render() {
    return (
      <div>
        <input type="text" onChange={this.changeFirstName} value={this.state.contact.firstName}/>
        <input type="text" onChange={this.changeLastName} value={this.state.contact.lastName}/>
        <input type="text" onChange={this.changePhone} value={this.state.contact.phone}/>
      </div>
    );
  }
}

La manière "intelligente", ES2015 +

Notez que handleChangeFor est une fonction curry _: L'appeler avec une propertyName crée une fonction de rappel qui, lorsqu'elle est appelée, met à jour [propertyName] de l'objet contact (Nouveau) dans l'état.

class ContactEdit extends React.Component {

  handleChangeFor = (propertyName) => (event) => {
    const { contact } = this.state;
    const newContact = {
      ...contact,
      [propertyName]: event.target.value
    };
    this.setState({ contact: newContact });
  }

  render() {
    return (
      <div>
        <input type="text" onChange={this.handleChangeFor('firstName')} value={this.state.contact.firstName}/>
        <input type="text" onChange={this.handleChangeFor('lastName')} value={this.state.contact.lastName}/>
        <input type="text" onChange={this.handleChangeFor('phone')} value={this.state.contact.lastName}/>
      </div>
    );
  }
}
55
ArneHugo

ES6 approche one liner

<input type="text" 
       value={this.state.username}
       onChange={(e) => this.setState({ username: e.target.value })}
       id="username"/>
8
Stuart P.

Il existe deux manières de mettre à jour l'état d'un objet imbriqué:

  1. Utilisez JSON.parse (JSON.stringify (objet)) pour créer une copie de l'objet, puis mettez à jour la copie et transmettez-la à setState.
  2. Utilisez les aides de l’immutabilité dans react-addons , qui est la méthode recommandée.

Vous pouvez voir comment cela fonctionne dans ce JS Fiddle . Le code est également ci-dessous:

var Component = React.createClass({
    getInitialState: function () {
    return ({contact: {firstName: "first", lastName: "last", phone: "1244125"}});
  },
  handleChange: function (key,event) {
    console.log(key,event.target.value);

    //way 1 
    //var updatedContact = JSON.parse(JSON.stringify(this.state.contact));
    //updatedContact[key] = event.target.value;

    //way 2 (Recommended)
    var updatedContact = React.addons.update(this.state.contact, {
        [key] : {$set: event.target.value}
    });
    this.setState({contact: updatedContact});
  },
  render: function () {
    return (
        <div>
          <input type="text" onChange={this.handleChange.bind(this,"firstName")} value={this.state.contact.firstName}/>
          <input type="text" onChange={this.handleChange.bind(this,"lastName")} value={this.state.contact.lastName}/>
          <input type="text" onChange={this.handleChange.bind(this,"phone")} value={this.state.contact.phone}/>
        </div>
      );
    }
});

ReactDOM.render(
  <Component />,
  document.getElementById('container')
);
2
Mark

Voici un générique;

handleChange = (input) => (event) => {
    this.setState({
        ...this.state,
        [input]: event.target.value
    });
}

Et utiliser comme ça;

<input handleChange ={this.handleChange("phone")} value={this.state.phone}/>
1
MmtBkn

L'approche la plus soignée

Voici une approche que j'ai utilisée dans mon application simple. C'est l'approche recommandée dans React et c'est vraiment net et net. C'est très proche de la réponse d'ArneHugo et je le remercie aussi. L'idée est un mélange de cela et de site de formes de réaction. Nous pouvons utiliser l'attribut name de chaque entrée de formulaire pour obtenir le propertyName spécifique et mettre à jour l'état en fonction de cela. Voici mon code dans ES6 pour l'exemple ci-dessus:

class ContactEdit extends React.Component {

  handleChangeFor = (event) => {
    const name = event.target.name;
    const value = event.target.value;
    const { contact } = this.state;
    const newContact = {
      ...contact,
      [name]: value
    };
    this.setState({ contact: newContact });
  }

  render() {
    return (
      <div>
        <input type="text" name="firstName" onChange={this.handleChangeFor} />
        <input type="text" name="lastName" onChange={this.handleChangeFor}/>
        <input type="text" name="phone" onChange={this.handleChangeFor}/>
      </div>
    );
  }
}

Les différences:

  • Nous n'avons pas besoin d'attribuer l'état en tant qu'attribut value. Aucune valeur n'est nécessaire
  • La méthode onChange n'a pas besoin d'argument dans l'appel de la fonction car nous utilisons plutôt l'attribut name
  • Nous déclarons le nom et la valeur de chaque entrée dans le début et les utilisons pour définir correctement l'état dans le code et nous utilisons les raquettes pour name car il s'agit d'un attribut.

Nous avons moins de code ici et un moyen très intelligent d’obtenir une entrée quelconque dans le formulaire car l’attribut name aura une valeur unique pour chaque entrée. Voir un exemple de travail exemple dans CodPen pour mon application de blog expérimental à ses débuts. 

1
azad6026

Les éléments <input> ont souvent une propriété appelée nom . Nous pouvons accéder à cette propriété name à partir de l'objet événement que nous recevons d'un gestionnaire d'événements:

Ecrire un gestionnaire de changement généralisé

constructor () {
    super();
    this.state = {
      name: '',
      age: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange (evt) {      
    this.setState({ [evt.target.name]: evt.target.value });
  }

render () {
    return (
      <form>

        <label>Name</label>
        <input type="text" name="name" onChange={this.handleChange} />

        <label>Age</label>
        <input type="text" name="age" onChange={this.handleChange} />

      </form>
    );
  }

la source

0
Dhruv Raval
handleChange(event){
    this.setState({[event.target.name]:event.target.value});
    this.setState({[event.target.name]:event.target.value});
  }
0
Karan Chunara