React js onClick ne peut pas transmettre de valeur à la méthode


639

Je souhaite lire les propriétés de la valeur de l'événement onClick. Mais quand je clique dessus, je vois quelque chose comme ça sur la console:

SyntheticMouseEvent {dispatchConfig: Object, dispatchMarker: ".1.1.0.2.0.0:1", nativeEvent: MouseEvent, type: "click", target

Mon code fonctionne correctement. Quand je cours, je peux voir {column}mais je ne peux pas l'obtenir dans l'événement onClick.

Mon code:

var HeaderRows = React.createClass({
  handleSort:  function(value) {
    console.log(value);
  },
  render: function () {
    var that = this;
    return(
      <tr>
        {this.props.defaultColumns.map(function (column) {
          return (
            <th value={column} onClick={that.handleSort} >{column}</th>
          );
        })}
        {this.props.externalColumns.map(function (column) {
          // Multi dimension array - 0 is column name
          var externalColumnName = column[0];
          return ( <th>{externalColumnName}</th>);
        })}
      </tr>
    );
  }
});

Comment puis-je transmettre une valeur à l' onClickévénement dans React js?



2
envisager d'utiliser soi-même au lieu de cela. C'est assez trompeur car cela devrait être synonyme de "ceci" (pas vraiment important cependant, pour chacun le sien)
Dan

En utilisant la méthode de liaison et la méthode de flèche, nous pouvons transmettre la valeur à l'événement
Onclick

Réponses:


1287

Moyen facile

Utilisez une fonction de flèche:

return (
  <th value={column} onClick={() => this.handleSort(column)}>{column}</th>
);

Cela créera une nouvelle fonction qui appelle handleSortavec les bons paramètres.

Meilleure façon

Extrayez-le dans un sous-composant. Le problème avec l'utilisation d'une fonction fléchée dans l'appel de rendu est qu'il créera une nouvelle fonction à chaque fois, ce qui finira par provoquer des restitutions inutiles.

Si vous créez un sous-composant, vous pouvez passer le gestionnaire et utiliser les accessoires comme arguments, qui ne seront ensuite restitués que lorsque les accessoires changent (car la référence du gestionnaire ne change plus):

Sous-composant

class TableHeader extends Component {
  handleClick = () => {
    this.props.onHeaderClick(this.props.value);
  }

  render() {
    return (
      <th onClick={this.handleClick}>
        {this.props.column}
      </th>
    );
  }
}

Composant principal

{this.props.defaultColumns.map((column) => (
  <TableHeader
    value={column}
    onHeaderClick={this.handleSort}
  />
))}

Old Easy Way (ES5)

Utilisez .bindpour passer le paramètre souhaité:

return (
  <th value={column} onClick={that.handleSort.bind(that, column)}>{column}</th>
);

7
réagir donne un avertissement lorsque j'utilise comme votre code. Je change mon code en onClick = {that.onClick.bind (null, colonne)}
user1924375

12
Comment utiliseriez-vous cela avec une <a>balise où vous devez passer l'événement, afin d'utiliserpreventDefault()
Simon H

38
@SimonH L'événement sera passé comme dernier argument, après les arguments que vous passez bind.
bavure

47
N'est-ce pas mauvais pour la performance? une nouvelle fonction ne sera-t-elle pas créée sur chaque rendu?
AndrewMcLagan

13
@AndrewMcLagan C'est ça. J'ai trouvé cela pour décrire la règle et la solution la plus performante.
E. Sundin

140

Il y a de bonnes réponses ici, et je suis d'accord avec @Austin Greco (la deuxième option avec des composants séparés)
Il y a une autre façon que j'aime, le curry .
Ce que vous pouvez faire est de créer une fonction qui accepte un paramètre (votre paramètre) et renvoie une autre fonction qui accepte un autre paramètre (l'événement click dans ce cas). alors vous êtes libre d'en faire ce que vous voulez.

ES5:

handleChange(param) { // param is the argument you passed to the function
    return function (e) { // e is the event object that returned

    };
}

ES6:

handleChange = param => e => {
    // param is the argument you passed to the function
    // e is the event object that returned
};

Et vous l'utiliserez de cette façon:

<input 
    type="text" 
    onChange={this.handleChange(someParam)} 
/>

Voici un exemple complet d'une telle utilisation:

Notez que cette approche ne résout pas la création d'une nouvelle instance sur chaque rendu.
J'aime cette approche par rapport aux autres gestionnaires en ligne car celle-ci est plus concise et lisible à mon avis.

Modifier:
Comme suggéré dans les commentaires ci-dessous, vous pouvez mettre en cache / mémoriser le résultat de la fonction.

Voici une implémentation naïve:


12
Ce devrait être la réponse acceptée. VRAIMENT facile à implémenter et vous n'avez pas besoin de créer d'autres composants ou de lier différemment. Je vous remercie!
Tamb

29
Cela semble mieux, mais du point de vue des performances, le curry n'aide pas vraiment, car si vous appelez handleChange deux fois, avec le même paramètre, vous obtenez deux fonctions que le moteur JS considère comme des objets distincts, même s'ils font la même chose . Vous obtenez donc toujours un nouveau rendu. Pour des raisons de performances, vous devez mettre en cache les résultats de handleChange pour obtenir l'avantage de performances. CommehandleChange = param => cache[param] || (e => { // the function body })
travellingprog

6
C'est la réponse parfaite si vous suivez les conseils de @travellingprog
llioor

2
Quelqu'un peut-il fournir un lien ou expliquer comment ce mécanisme de mise en cache fonctionne? Merci.
Sadok Mtir

2
Beau et soigné!
Hatem Alimam

117

De nos jours, avec ES6, je pense que nous pourrions utiliser une réponse mise à jour.

return (
  <th value={column} onClick={()=>this.handleSort(column)} >{column}</th>
);

Fondamentalement, (pour ceux qui ne le savent pas) car onClickattend une fonction qui lui est transmise, bindfonctionne car il crée une copie d'une fonction. Au lieu de cela, nous pouvons passer une expression de fonction de flèche qui appelle simplement la fonction que nous voulons et conserve this. Vous ne devriez jamais avoir besoin de lier la renderméthode dans React, mais si pour une raison quelconque vous perdez thisdans l'une de vos méthodes de composant:

constructor(props) {
  super(props);
  this.myMethod = this.myMethod.bind(this);
}

10
Vous n'avez jamais besoin de lier render()car il est appelé par React. Si quoi que ce soit, vous avez besoin binddes gestionnaires d'événements, et uniquement lorsque vous n'utilisez pas de flèches.
Dan Abramov

1
@DanAbramov Je pense que vous avez raison, mais je l'ai inclus juste au cas où - mis à jour avec un exemple qui n'encourage pas implicitement le rendu de liaison.
aikeru

3
Notez qu'il est également préférable de passer propsà super()ou this.propsne sera pas défini pendant le constructeur, ce qui peut prêter à confusion.
Dan Abramov

2
Pour réaliser quoi? Vous pouvez définir un gestionnaire à l'intérieur du composant fonctionnel et le transmettre. Ce sera une fonction différente à chaque rendu, donc si vous avez déterminé avec un profileur qu'il vous pose des problèmes de performance (et seulement si vous êtes vraiment sûr de cela!), Envisagez d'utiliser une classe à la place.
Dan Abramov

1
@ me-me Oui, et si vous optez pour le JavaScript à la pointe de la technologie dans Babel, vous devez simplement déclarer des propriétés sur votre classe comme foo = () => {...}et y faire référence pour rendre <button onClick={this.foo}...la seule raison d'inclure une fonction de flèche si vous utilisez babel de cette manière, IMO, est si vous voulez capturer une variable qui n'existe que dans la portée de la méthode render () (les événements peuvent simplement être transmis et ne s'appliquent pas).
aikeru

73

[[h / t à @ E.Sundin pour avoir lié ceci dans un commentaire]

La première réponse (fonctions anonymes ou liaison) fonctionnera, mais ce n'est pas la plus performante, car elle crée une copie du gestionnaire d'événements pour chaque instance générée par la map()fonction.

Ceci est une explication de la façon optimale de le faire à partir du plugin ESLint-react :

Listes d'articles

Un cas d'utilisation courant de liaison dans le rendu est lors du rendu d'une liste, pour avoir un rappel séparé par élément de liste:

const List = props => (
      <ul>
        {props.items.map(item =>
          <li key={item.id} onClick={() => console.log(item.id)}>
            ...
          </li>
        )}
      </ul>
    );

Plutôt que de le faire de cette façon, tirez la section répétée dans son propre composant:

const List = props => (
      <ul>
        {props.items.map(item =>
          <ListItem 
            key={item.id} 
            item={item} 
            onItemClick={props.onItemClick} // assume this is passed down to List
           />
        )}
      </ul>
    );


const ListItem = props => {
  const _onClick = () => {
    console.log(props.item.id);
  }
    return (
      <li onClick={_onClick}>
        ...
      </li>
    );

});

Cela accélérera le rendu, car il évite de créer de nouvelles fonctions (via des appels de liaison) à chaque rendu.


React appelle-t-il ces fonctions avec call / apply, puis, sous le capot, et évite-t-il d'utiliser bind en interne?
aikeru

1
Existe-t-il un moyen de le faire en utilisant un composant sans état?
Carlos Martinez

2
@CarlosMartinez bon œil, j'ai mis à jour l'exemple - ils auraient dû être des composants fonctionnels sans état (SFC) en premier lieu. Généralement, si un composant n'utilise jamais this.state, vous pouvez l'échanger en toute sécurité avec un SFC.
Brandon

3
Hmm, je ne comprends pas comment c'est plus performant? La fonction ListItem ne sera pas invoquée à chaque fois, et donc la fonction _onClick sera créée à chaque rendu.
Mattias Petter Johansson

1
Je suis loin d'être un expert ici, mais si je comprends bien, dans le modèle `` correct '', il n'y a qu'une seule instance du gestionnaire et il a été propulsé par l'instance du composant qui l'appelle. Dans l'exemple de liaison (c'est-à-dire, le «mauvais» modèle), il y a une instance du gestionnaire pour chaque composant instancié. C'est en quelque sorte l'équivalent en mémoire d'écrire trente fois la même fonction et de l'écrire une fois et de l'appeler là où c'est nécessaire.
Brandon

25

Ceci est mon approche, je ne sais pas à quel point c'est mauvais, veuillez commenter

Dans l'élément cliquable

return (
    <th value={column} onClick={that.handleSort} data-column={column}>   {column}</th>
);

et alors

handleSort(e){
    this.sortOn(e.currentTarget.getAttribute('data-column'));
}

C'est une approche à laquelle je pensais, ça fait un peu hacky mais ça évite de créer un nouveau composant. Je ne suis pas sûr que getAttribute soit meilleur ou pire en termes de performances que de tirer dans un composant séparé.
kamranicus

2
Je pense que c'est une bonne solution car c'est très simple. Mais cela ne fonctionne qu'avec des valeurs de chaîne, si vous voulez un objet, cela ne fonctionne pas.
Stephane L

Pour un objet que vous devez faire encodeURIComponent(JSON.stringify(myObj)), puis de l' analyser, JSON.parse(decodeURIComponent(myObj)). Pour les fonctions, je suis presque sûr que cela ne fonctionnera pas sans eval ou new Function (), qui devraient être évités. Pour ces raisons, je n'utilise pas d'attributs de données pour transmettre des données dans React / JS.
Solvitieg

Je veux ajouter que je ne l'utilise pas souvent et seulement pour des choses mineures. Mais généralement, je crée simplement un composant et lui transmets les données comme accessoires. Ensuite, gérez le clic à l'intérieur de ce nouveau composant ou passez une fonction onClick au composant. Comme expliqué dans la réponse de Brandon
Santiago Ramirez

1
l'ensemble de données est accessible directement de cette manière sur les navigateurs modernes (y compris IE11): e.currentTarget.dataset.column
gsziszi

17

cet exemple peut être légèrement différent du vôtre. mais je peux vous assurer que c'est la meilleure solution que vous pouvez avoir pour ce problème. j'ai cherché pendant des jours une solution qui n'a aucun problème de performance. et a finalement trouvé celui-ci.

class HtmlComponent extends React.Component {
  constructor() {
    super();
    this.state={
       name:'MrRehman',
    };
    this.handleClick= this.handleClick.bind(this);
  }

  handleClick(event) {
    const { param } = e.target.dataset;
    console.log(param);
    //do what you want to do with the parameter
  }

  render() {
    return (
      <div>
        <h3 data-param="value what you wanted to pass" onClick={this.handleClick}>
          {this.state.name}
        </h3>
      </div>
    );
  }
}

MISE À JOUR

dans le cas où vous souhaitez traiter des objets qui sont censés être les paramètres. vous pouvez l'utiliser JSON.stringify(object)pour le convertir en chaîne et l'ajouter à l'ensemble de données.

return (
   <div>
     <h3 data-param={JSON.stringify({name:'me'})} onClick={this.handleClick}>
        {this.state.name}
     </h3>
   </div>
);

1
cela ne fonctionne pas lorsque les données transmises sont un objet
SlimSim

utilisez JSON.stringify pour résoudre le problème. @SlimSim. ça devrait faire l'affaire
hannad rehman

Si vous devez utiliser JSON.stringify pour ce problème, ce n'est probablement pas la bonne méthode. Le processus de stringification prend beaucoup de mémoire.
KFE

dans la plupart des cas, vous ne passeriez que l'ID en tant que paramètres et vous obtiendriez les détails de l'objet en fonction de cet ID à partir de votre objet source. et pourquoi et comment cela prend-il beaucoup de mémoire, je sais que JSON stringify est lent, mais le clic Fn est asynchrone et il n'aura aucun effet ou aucun effet sur dom, une fois construit
hannad rehman

6
class extends React.Component {
    onClickDiv = (column) => {
        // do stuff
    }
    render() {
        return <div onClick={() => this.onClickDiv('123')} />
    }
}

2
Le même - nouveau DOM sur chaque rendu. React mettra donc à jour DOM à chaque fois.
Alex Shwarc

4

Une autre option n'impliquant pas .bindou ES6 consiste à utiliser un composant enfant avec un gestionnaire pour appeler le gestionnaire parent avec les accessoires nécessaires. Voici un exemple (et un lien vers un exemple de travail est ci-dessous):

var HeaderRows = React.createClass({
  handleSort:  function(value) {
     console.log(value);
  },
  render: function () {
      var that = this;
      return(
          <tr>
              {this.props.defaultColumns.map(function (column) {
                  return (
                      <TableHeader value={column} onClick={that.handleSort} >
                        {column}
                      </TableHeader>
                  );
              })}
              {this.props.externalColumns.map(function (column) {
                  // Multi dimension array - 0 is column name
                  var externalColumnName = column[0];
                  return ( <th>{externalColumnName}</th>
                  );
              })}
          </tr>);
      )
  }
});

// A child component to pass the props back to the parent handler
var TableHeader = React.createClass({
  propTypes: {
    value: React.PropTypes.string,
    onClick: React.PropTypes.func
  },
  render: function () {
    return (
      <th value={this.props.value} onClick={this._handleClick}
        {this.props.children}
      </th>
    )        
  },
  _handleClick: function () {
    if (this.props.onClick) {
      this.props.onClick(this.props.value);
    }
  }
});

L'idée de base est que le composant parent transmette la onClickfonction à un composant enfant. Le composant enfant appelle la onClickfonction et peut accéder à tous ceux qui lui sont propstransmis (et à event), ce qui vous permet d'utiliser n'importe quelle eventvaleur ou d'autres accessoires dans la onClickfonction du parent .

Voici une démonstration de CodePen montrant cette méthode en action.


4

Faire une autre tentative pour répondre à la question de OP, y compris les appels e.preventDefault ():

Lien rendu ( ES6 )

<a href="#link" onClick={(e) => this.handleSort(e, 'myParam')}>

Fonction des composants

handleSort = (e, param) => {
  e.preventDefault();
  console.log('Sorting by: ' + param)
}

4

Je me rends compte que c'est assez tard pour la fête, mais je pense qu'une solution beaucoup plus simple pourrait satisfaire de nombreux cas d'utilisation:

    handleEdit(event) {
        let value = event.target.value;
    }

    ...

    <button
        value={post.id}
        onClick={this.handleEdit} >Edit</button>

Je suppose que vous pouvez également utiliser un data-attribut.

Simple, sémantique.


4

Créez simplement une fonction comme celle-ci

  function methodName(params) {
    //the thing  you wanna do
  }

et appelez-le à l'endroit dont vous avez besoin

<Icon onClick = {() => {methodName (theParamsYouwantToPass); }} />


3

Vous pouvez simplement le faire si vous utilisez ES6.

export default class Container extends Component {
  state = {
    data: [
        // ...
    ]
  }

  handleItemChange = (e, data) => {
      // here the data is available 
      // ....
  }
  render () {
     return (
        <div>
        {
           this.state.data.map((item, index) => (
              <div key={index}>
                  <Input onChange={(event) => this.handItemChange(event, 
                         item)} value={item.value}/>
              </div>
           ))
        }
        </div>
     );
   }
 }

3

L'implémentation affiche le nombre total à partir d'un objet en transmettant le nombre en tant que paramètre du composant principal aux composants secondaires, comme décrit ci-dessous.

Voici MainComponent.js

import React, { Component } from "react";

import SubComp from "./subcomponent";

class App extends Component {

  getTotalCount = (count) => {
    this.setState({
      total: this.state.total + count
    })
  };

  state = {
    total: 0
  };

  render() {
    const someData = [
      { name: "one", count: 200 },
      { name: "two", count: 100 },
      { name: "three", count: 50 }
    ];
    return (
      <div className="App">
        {someData.map((nameAndCount, i) => {
          return (
            <SubComp
              getTotal={this.getTotalCount}
              name={nameAndCount.name}
              count={nameAndCount.count}
              key={i}
            />
          );
        })}
        <h1>Total Count: {this.state.total}</h1>
      </div>
    );
  }
}

export default App;

Et voici SubComp.js

import React, { Component } from 'react';
export default class SubComp extends Component {

  calculateTotal = () =>{
    this.props.getTotal(this.props.count);
  }

  render() {
    return (
      <div>
        <p onClick={this.calculateTotal}> Name: {this.props.name} || Count: {this.props.count}</p>
      </div>
    )
  }
};

Essayez d'implémenter ci-dessus et vous obtiendrez un scénario exact indiquant comment les paramètres de passage fonctionnent dans reactjs sur n'importe quelle méthode DOM.


3

J'ai écrit un composant wrapper qui peut être réutilisé à cet effet qui s'appuie sur les réponses acceptées ici. Si tout ce que vous devez faire est de passer une chaîne, ajoutez simplement un attribut de données et lisez-le depuis e.target.dataset (comme certains l'ont suggéré). Par défaut, mon wrapper se liera à tout accessoire qui est une fonction et commence par «on» et retransmet automatiquement l'accessoire de données à l'appelant après tous les autres arguments d'événement. Bien que je ne l'ai pas testé pour les performances, cela vous donnera l'occasion d'éviter de créer la classe vous-même, et il peut être utilisé comme ceci:

const DataButton = withData('button')
const DataInput = withData('input');

ou pour Composants et fonctions

const DataInput = withData(SomeComponent);

ou si vous préférez

const DataButton = withData(<button/>)

déclarer qu'en dehors de votre conteneur (près de vos importations)

Voici l'utilisation dans un conteneur:

import withData from './withData';
const DataInput = withData('input');

export default class Container extends Component {
    state = {
         data: [
             // ...
         ]
    }

    handleItemChange = (e, data) => {
        // here the data is available 
        // ....
    }

    render () {
        return (
            <div>
                {
                    this.state.data.map((item, index) => (
                        <div key={index}>
                            <DataInput data={item} onChange={this.handleItemChange} value={item.value}/>
                        </div>
                    ))
                }
            </div>
        );
    }
}

Voici le code wrapper 'withData.js:

import React, { Component } from 'react';

const defaultOptions = {
    events: undefined,
}

export default (Target, options) => {
    Target = React.isValidElement(Target) ? Target.type : Target;
    options = { ...defaultOptions, ...options }

    class WithData extends Component {
        constructor(props, context){
            super(props, context);
            this.handlers = getHandlers(options.events, this);        
        }

        render() {
            const { data, children, ...props } = this.props;
            return <Target {...props} {...this.handlers} >{children}</Target>;
        }

        static displayName = `withData(${Target.displayName || Target.name || 'Component'})`
    }

    return WithData;
}

function getHandlers(events, thisContext) {
    if(!events)
        events = Object.keys(thisContext.props).filter(prop => prop.startsWith('on') && typeof thisContext.props[prop] === 'function')
    else if (typeof events === 'string')
        events = [events];

    return events.reduce((result, eventType) => {
        result[eventType] = (...args) => thisContext.props[eventType](...args, thisContext.props.data);
        return result;
    }, {});
}

2

J'ai ci-dessous 3 suggestions à ce sujet sur JSX onClick Events -

  1. En fait, nous n'avons pas besoin d'utiliser la fonction .bind () ou Arrow dans notre code. Vous pouvez une utilisation simple dans votre code.

  2. Vous pouvez également déplacer l'événement onClick de th (ou ul) à tr (ou li) pour améliorer les performances. Fondamentalement, vous aurez n nombre d '"écouteurs d'événements" pour votre élément n li.

    So finally code will look like this:
    <ul onClick={this.onItemClick}>
        {this.props.items.map(item =>
               <li key={item.id} data-itemid={item.id}>
                   ...
               </li>
          )}
    </ul>

    // Et vous pouvez accéder item.idà la onItemClickméthode comme indiqué ci-dessous:

    onItemClick = (event) => {
       console.log(e.target.getAttribute("item.id"));
    }
  3. Je suis d'accord avec l'approche mentionnée ci-dessus pour créer un composant React séparé pour ListItem et List. Ce code de rendu semble bon, mais si vous en avez 1000, alors 1000 écouteurs d'événements seront créés. Veuillez vous assurer que vous ne devriez pas avoir beaucoup d'auditeur d'événements.

    import React from "react";
    import ListItem from "./ListItem";
    export default class List extends React.Component {
    
        /**
        * This List react component is generic component which take props as list of items and also provide onlick
        * callback name handleItemClick
        * @param {String} item - item object passed to caller
        */
        handleItemClick = (item) => {
            if (this.props.onItemClick) {
                this.props.onItemClick(item);
            }
        }
    
        /**
        * render method will take list of items as a props and include ListItem component
        * @returns {string} - return the list of items
        */
        render() {
            return (
                <div>
                  {this.props.items.map(item =>
                      <ListItem key={item.id} item={item} onItemClick={this.handleItemClick}/>
                  )}
                </div>
            );
        }
    
    }
    
    
    import React from "react";
    
    export default class ListItem extends React.Component {
        /**
        * This List react component is generic component which take props as item and also provide onlick
        * callback name handleItemClick
        * @param {String} item - item object passed to caller
        */
        handleItemClick = () => {
            if (this.props.item && this.props.onItemClick) {
                this.props.onItemClick(this.props.item);
            }
        }
        /**
        * render method will take item as a props and print in li
        * @returns {string} - return the list of items
        */
        render() {
            return (
                <li key={this.props.item.id} onClick={this.handleItemClick}>{this.props.item.text}</li>
            );
        }
    }

1
Cela ne fonctionne pas lorsque les données que vous devez transmettre sont un objet. L'attribut ne fonctionnera qu'avec des chaînes. La lecture à partir du dom via l'attribut get est probablement une opération plus coûteuse.
SlimSim

2

J'ai ajouté du code pour passer la valeur de l'événement onclick à la méthode de deux manières. 1 . en utilisant la méthode bind 2. en utilisant la méthode arrow (=>). voir les méthodes handlesort1 et handlesort

var HeaderRows  = React.createClass({
    getInitialState : function() {
      return ({
        defaultColumns : ["col1","col2","col2","col3","col4","col5" ],
        externalColumns : ["ecol1","ecol2","ecol2","ecol3","ecol4","ecol5" ],

      })
    },
    handleSort:  function(column,that) {
       console.log(column);
       alert(""+JSON.stringify(column));
    },
    handleSort1:  function(column) {
       console.log(column);
       alert(""+JSON.stringify(column));
    },
    render: function () {
        var that = this;
        return(
        <div>
            <div>Using bind method</div>
            {this.state.defaultColumns.map(function (column) {
                return (
                    <div value={column} style={{height : '40' }}onClick={that.handleSort.bind(that,column)} >{column}</div>
                );
            })}
            <div>Using Arrow method</div>

            {this.state.defaultColumns.map(function (column) {
                return (
                    <div value={column} style={{height : 40}} onClick={() => that.handleSort1(column)} >{column}</div>

                );
            })}
            {this.state.externalColumns.map(function (column) {
                // Multi dimension array - 0 is column name
                var externalColumnName = column;
                return (<div><span>{externalColumnName}</span></div>
                );
            })}

        </div>);
    }
});

2

Voici l'exemple qui transmet la valeur à l'événement onClick.

J'ai utilisé la syntaxe es6. rappelez-vous que la fonction de flèche du composant de classe ne se lie pas automatiquement, donc la liaison explicitement dans le constructeur.

class HeaderRows extends React.Component {

    constructor(props) {
        super(props);
        this.handleSort = this.handleSort.bind(this);
    }

    handleSort(value) {
        console.log(value);
    }

    render() {
        return(
            <tr>
                {this.props.defaultColumns.map( (column, index) =>
                    <th value={ column } 
                        key={ index } 
                        onClick={ () => this.handleSort(event.target.value) }>
                        { column }
                    </th>
                )}

                {this.props.externalColumns.map((column, index)  =>
                    <th value ={ column[0] }
                        key={ index }>
                        {column[0]}
                    </th>
                )}
            </tr>
         );
    }
}

2

Je suppose que vous devrez lier la méthode à l'instance de classe React. Il est plus sûr d'utiliser un constructeur pour lier toutes les méthodes dans React. Dans votre cas, lorsque vous passez le paramètre à la méthode, le premier paramètre est utilisé pour lier le contexte «this» de la méthode, vous ne pouvez donc pas accéder à la valeur à l'intérieur de la méthode.


2
1. You just have to use an arrow function in the Onclick event like this: 

<th value={column} onClick={() => that.handleSort(theValue)} >{column}</th>

2.Then bind this in the constructor method:
    this.handleSort = this.handleSort.bind(this);

3.And finally get the value in the function:
  handleSort(theValue){
     console.log(theValue);
}

2

C'est un moyen très simple.

 onClick={this.toggleStart('xyz')} . 
  toggleStart= (data) => (e) =>{
     console.log('value is'+data);  
 }

2
class TableHeader extends Component {
  handleClick = (parameter,event) => {
console.log(parameter)
console.log(event)

  }

  render() {
    return (
      <button type="button" 
onClick={this.handleClick.bind(this,"dataOne")}>Send</button>
    );
  }
}

4
Bien que ce code puisse résoudre la question, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question des lecteurs à l'avenir et que ces personnes ne connaissent peut-être pas les raisons de votre suggestion de code.
Shree

2

Sortir de nulle part à cette question, mais je pense .bindque ça fera l'affaire. Trouvez l'exemple de code ci-dessous.

const handleClick = (data) => {
    console.log(data)
}

<button onClick={handleClick.bind(null, { title: 'mytitle', id: '12345' })}>Login</button>

1

Utilisation de la fonction flèche:

Vous devez installer l'étape 2:

npm install babel-preset-stage-2:

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            value=0
        }
    }

    changeValue = (data) => (e) => {
        alert(data);  //10
        this.setState({ [value]: data })
    }

    render() {
        const data = 10;
        return (
            <div>
                <input type="button" onClick={this.changeValue(data)} />
            </div>
        );
    }
}
export default App; 

0

Il y a 3 façons de gérer cela: -

  1. Liez la méthode dans le constructeur comme: -

    export class HeaderRows extends Component {
       constructor() {
           super();
           this.handleSort = this.handleSort.bind(this);
       }
    }
  2. Utilisez la fonction flèche lors de sa création comme: -

    handleSort = () => {
        // some text here
    }
  3. La troisième façon est la suivante: -

    <th value={column} onClick={() => that.handleSort} >{column}</th>

0

Vous pouvez utiliser votre code comme ceci:

<th value={column} onClick={(e) => that.handleSort(e, column)} >{column}</th>

Ici, c'est pour un objet d'événement, si vous souhaitez utiliser des méthodes d'événement comme preventDefault()dans votre fonction de poignée ou si vous voulez obtenir une valeur cible ou un nom comme e.target.name.


0

J'ai trouvé la solution de passer param comme attribut d'un tag tout à fait raisonnable.

Cependant, il a ses limites:

  • Ne fonctionne pas correctement lorsque l'élément de liste a d'autres balises (donc event.target peut être différent de celui prévu)
  • Param ne peut être qu'une chaîne. Nécessite la sérialisation et la désérialisation.

C'est pourquoi j'ai créé cette bibliothèque: react-event-param

Il:

  • Résout le problème des enfants en recherchant l'attribut nécessaire chez les parents chaque fois que nécessaire
  • Sérialise et désérialise automatiquement les paramètres
  • Encapsule la logique de définition et d'obtention. Pas besoin de jouer avec les noms des paramètres

Exemple d'utilisation:

import { setEventParam, getEventParam } from "react-event-param";

class List extends Component {
  onItemClick = e => {
    const index = getEventParam(e.target);
    // Do something with index
  };

  render() {
    return (
      <ul>
        {this.props.items.map((itemText, index) => (
          <li
            key={index}
            {...setEventParam(index)}
            onClick={this.onItemClick}
          >
            {{ itemText }}
          </li>
        ))}
      </ul>
    );
  }
}

export default List;

0

Il y avait beaucoup de considérations de performances, toutes dans le vide.
Le problème avec ces gestionnaires est que vous devez les curry afin d'incorporer l'argument que vous ne pouvez pas nommer dans les accessoires.
Cela signifie que le composant a besoin d'un gestionnaire pour chaque élément cliquable. Convenons que pour quelques boutons ce n'est pas un problème, non?
Le problème se pose lorsque vous manipulez des données tabulaires avec des dizaines de colonnes et des milliers de lignes. Là, vous remarquez l'impact de la création d'autant de gestionnaires.

Le fait est que je n'en ai besoin que d'un.
J'ai défini le gestionnaire au niveau de la table (ou UL ou OL ...), et lorsque le clic se produit, je peux dire quelle était la cellule cliquée en utilisant les données disponibles depuis toujours dans l'objet événement:

nativeEvent.target.tagName
nativeEvent.target.parentElement.tagName 
nativeEvent.target.parentElement.rowIndex
nativeEvent.target.cellIndex
nativeEvent.target.textContent

J'utilise les champs de variable pour vérifier que le clic s'est produit dans un élément valide, par exemple ignorer les clics dans les pieds de page des TH.
Le rowIndex et le cellIndex donnent l'emplacement exact de la cellule cliquée.
Le contenu du texte est le texte de la cellule cliquée.

De cette façon, je n'ai pas besoin de transmettre les données de la cellule au gestionnaire, il peut le self-service.
Si j'avais besoin de plus de données, de données qui ne doivent pas être affichées, je peux utiliser l'attribut d'ensemble de données ou des éléments cachés.
Avec une navigation DOM simple, tout est à portée de main.
Cela a été utilisé en HTML depuis toujours, car les PC étaient beaucoup plus faciles à embourber.


0

Il existe deux façons de passer des paramètres dans les gestionnaires d'événements, certains suivent.

Vous pouvez utiliser une fonction de flèche pour encapsuler un gestionnaire d'événements et transmettre des paramètres:

<button onClick={() => this.handleClick(id)} />

l'exemple ci-dessus équivaut à appeler .bindou vous pouvez explicitement appeler bind.

<button onClick={this.handleClick.bind(this, id)} />

En dehors de ces deux approches, vous pouvez également passer des arguments à une fonction définie comme une fonction curry.

handleClick = (id) => () => {
    console.log("Hello, your ticket number is", id)
};

<button onClick={this.handleClick(id)} />

-1

Utilisez une fermeture , il en résulte une solution propre:

<th onClick={this.handleSort(column)} >{column}</th>

La fonction handleSort renverra une fonction dont la colonne de valeur est déjà définie.

handleSort: function(value) { 
    return () => {
        console.log(value);
    }
}

La fonction anonyme sera appelée avec la valeur correcte lorsque l'utilisateur cliquera sur le th.

Exemple: https://stackblitz.com/edit/react-pass-parameters-example


-2

Un changement simple est requis:

Utilisation <th value={column} onClick={that.handleSort} >{column}</th>

au lieu de <th value={column} onClick={that.handleSort} >{column}</th>

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.