web-dev-qa-db-fra.com

Passer un paramètre supplémentaire avec un événement onChange

Ce que j'essaie de faire:

J'essaie de transmettre une chaîne d'un composant enfant à la fonction handleChange d'un composant parent.

Qu'est-ce qui fonctionne actuellement:

J'ai un parent React JS class avec la méthode suivante:

handleChange(event) {

    console.log(event.target.value);
}

Dans la fonction de rendu, j'ai les éléments suivants:

<Child handleChange={this.handleChange.bind(this)} />

Dans la classe des enfants, j'ai:

<fieldset onChange={this.props.handleChange}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>

Cela fonctionne bien.

Ce que j'essaie de faire à la place:

J'essaie d'ajouter un paramètre section à la fonction handleChange comme suit:

handleChange(section, event) {
    console.log(section);
    console.log(event.target.value);
}

Et dans la classe enfant, j'ai:

<fieldset onChange={this.props.handleChange("tags")}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>

Je reçois maintenant l'erreur:

Uncaught TypeError: Cannot read property 'target' of undefined

Cette erreur est renvoyée dans ma deuxième instruction console.log.

Qu'est-ce que je fais mal?

En outre, j’envisage de rendre le paramètre section facultatif. Si oui, existe-t-il un moyen facile de le faire? Il semble que cela ne soit peut-être pas possible si le paramètre d'événement doit être le dernier.

19
kojow7

Quand vous écrivez ceci:

<fieldset onChange={this.props.handleChange("tags")}>

handleChange sera appelé immédiatement dès que le rendu est déclenché.

Au lieu de cela, faites-le comme ceci:

<fieldset onChange={(e) => this.props.handleChange("tags", e)}>

Maintenant, le handleChange sera appelé lorsque le gestionnaire onChange sera appelé.

37
Ritesh Bansal

Dans votre événement handle, utilisez la fonction double flèche, il n’est pas nécessaire de vous lier lorsque vous utilisez la fonction flèche:

handleChange = tags => (event) => {
    console.log(tags);
    console.log(event.target.value);
}

Et chez l'enfant:

<fieldset onChange={this.props.handleChange("tags")}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>

En tant que PO, j’avais initialement posté ce message en guise de suivi de ma question, mais il a été supprimé et on m’a demandé de le poster en tant que réponse. Voici donc ce qui suit:

D'après la réponse de Ritesh Bansal, j'ai appris ce qui suit:

La ligne suivante ne fonctionnait pas car lors de l'utilisation de parenthèses après le nom de la fonction, la fonction est appelée immédiatement au lieu d'attendre qu'un changement se produise:

<fieldset onChange={this.props.handleChange("tags")}>

Ce qui précède ne fonctionnera pas, pas plus qu'une fonction comme celle-ci:

<fieldset onChange={this.props.handleChange()}>

Ce qui précède serait également appelé immédiatement lors du premier rendu.

Il y a deux solutions à cela:

Le moins bon moyen:

<fieldset onChange={this.props.handleChange.bind(this, "tags")}>

Le meilleur moyen:

<fieldset onChange={(evt) => this.props.handleChange("tags", evt)}>

Le problème est maintenant résolu. Merci tout le monde!

Mise à jour:

J'ai également étudié la suggestion de Shubham Khatri de modifier l'élément enfant en ceci:

<Child handleChange={(e,val) => this.handleChange(e, val)}/>

Je n'avais pas compris qu'en utilisant bind dans la fonction de rendu, chaque fois que le rendu s'appelait, il créait une nouvelle instance de fonction. Je peux donc utiliser la méthode de Shubham Khatri ou lier les méthodes dans le constructeur.

3
kojow7

Aucune fonction anonyme définie sur chaque rendu () :

La plupart des réponses ici recommandent une fonction anonyme définie dans render (), qui, comme Davidicus l’a souligné, n’est pas recommandée: https://medium.freecodecamp.org/why-arrow-functions-and-bind- in-reacts-render-are-problematic-f1c08b060e36

La réponse de François évite ce problème, mais comme l'a souligné Vael Victus, cela nécessite transform-class-properties.

Cependant, il ne fait que définir une fonction qui définit une fonction, ce que vous pouvez sinon faire comme ceci:

constructor(props) {
  super(props);
  this.handleChange = (yourSpecialParam) => (event) => this.handleChange(yourSpecialParam).bind(this)
}

render() {
  return <button onClick={this.handleChange(1234)} >Click Me</button>
}
2
kalzen

Tu peux le faire:

<fieldset onChange={(e) => this.props.handleChange("tags", e)}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>
1
Omri Aharon

Pour passer un paramètre du composant enfant au parent, vous pouvez utiliser un argument pour la fonction arrow.

handleChange(event, section) {
    console.log(section);
    console.log(event.target.value);
}
<Child handleChange={(e, val) => this.handleChange(e, val)} />

<fieldset onChange={(e) => this.props.handleChange(e, "tags")}>
    <div>Tag 1: <input id="tag1" value={tags[0]} /></div>
    <div>Tag 2: <input id="tag2" value={tags[1]} /></div>
    <div>Tag 3: <input id="tag3" value={tags[2]} /></div>
</fieldset>

Échantillon extrait

class App extends React.Component {
  handleChange(e, val) {
    console.log(e.target.value, val);
  }
  render() {
    return(
      <Child handleChange={(e,val) => this.handleChange(e, val)}/>
    )
  }
}

class Child extends React.Component {
  
  render() {
    return(
      <input type="text" onChange={(e) => this.props.handleChange(e, 'tab')}/>
    )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'));
<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>
1
Shubham Khatri