React js onClick nie może przekazać wartości do metody

638

Chcę przeczytać właściwości wartości zdarzenia onClick. Ale kiedy klikam, widzę coś takiego na konsoli:

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

Mój kod działa poprawnie. Kiedy uruchamiam, widzę, {column}ale nie mogę dostać tego w zdarzeniu onClick.

Mój kod:

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

Jak mogę przekazać wartość do onClickzdarzenia w React js?

użytkownik1924375
źródło
2
możliwy duplikat wiązania zdarzenia OnClick w
React.js
2
rozważ użycie self zamiast tego. Jest to dość mylące, ponieważ powinno być równoznaczne z „tym” (choć nie jest to tak naprawdę ważne dla każdego z nich)
Dan
Za pomocą metody bind i metody strzałki możemy przekazać wartość do zdarzenia
Onclick
1
zobacz ten przykład Przekazywanie parametrów do funkcji strzałki w reakcji js
sumit kumar pradhan

Odpowiedzi:

1285

Łatwy sposób

Użyj funkcji strzałki:

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

Spowoduje to utworzenie nowej funkcji, która będzie wywoływać handleSortz odpowiednimi parametrami.

Lepszy sposób

Wyodrębnij go do podskładnika. Problem z użyciem funkcji strzałki w wywołaniu renderowania polega na tym, że za każdym razem tworzy ona nową funkcję, co powoduje niepotrzebne ponowne renderowanie.

Jeśli utworzysz podskładnik, możesz przekazać moduł obsługi i użyć rekwizytów jako argumentów, co spowoduje ponowne renderowanie tylko po zmianie rekwizytów (ponieważ odwołanie do modułu obsługi nigdy się nie zmienia):

Podskładnik

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

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

Główny składnik

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

Old Easy Way (ES5)

Użyj, .bindaby przekazać żądany parametr:

return (
  <th value={column} onClick={that.handleSort.bind(that, column)}>{column}</th>
);
Austin Greco
źródło
7
reaguje daje ostrzeżenie, gdy używam jak twój kod. Zmieniam kod na onClick = {that.onClick.bind (null, column)}
user1924375
12
Jak użyłbyś tego z <a>tagiem, w którym musisz przekazać zdarzenie, aby użyćpreventDefault()
Simon H
38
@ SimonH Zdarzenie zostanie przekazane jako ostatni argument, po argumentach, które przekazujesz bind.
rozmazywanie
47
Czy to nie jest złe dla wydajności? czy na każdym renderowaniu nie zostanie utworzona nowa funkcja?
AndrewMcLagan
13
@AndrewMcLagan It is. I znaleźć to opisać zasady i najbardziej wydajnych rozwiązań.
E. Sundin,
140

Tutaj są fajne odpowiedzi i zgadzam się z @Austin Greco (druga opcja z osobnymi komponentami)
Jest inny sposób, w jaki lubię, curry .
Możesz stworzyć funkcję, która akceptuje parametr (twój parametr) i zwraca inną funkcję, która akceptuje inny parametr (w tym przypadku zdarzenie kliknięcia). możesz robić z tym, co chcesz.

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
};

I wykorzystasz to w ten sposób:

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

Oto pełny przykład takiego użycia:

Zauważ, że to podejście nie rozwiązuje problemu tworzenia nowej instancji na każdym renderowaniu.
Podoba mi się to podejście w porównaniu do innych programów obsługi inline, ponieważ moim zdaniem jest to bardziej zwięzłe i czytelne.

Edycja:
Jak sugerowano w komentarzach poniżej, możesz buforować / zapamiętać wynik działania funkcji.

Oto naiwna implementacja:

Sagiv bg
źródło
12
To powinna być zaakceptowana odpowiedź. NAPRAWDĘ łatwe do wdrożenia i nie trzeba tworzyć żadnych innych komponentów ani wiązać inaczej. Dziękuję Ci!
Tamb
29
Wygląda lepiej, ale z punktu widzenia wydajności curry naprawdę nie pomaga, ponieważ dwukrotne wywołanie metody handleChange z tym samym parametrem daje dwie funkcje, które silnik JS uważa za osobne obiekty, nawet jeśli robią to samo . Więc nadal otrzymujesz ponowne renderowanie. Ze względu na wydajność należy buforować wyniki metody handleChange, aby uzyskać przewagę wydajności. LikehandleChange = param => cache[param] || (e => { // the function body })
travellingprog
6
To idealna odpowiedź, jeśli zastosujesz się do porady @travellingprog
llioor,
2
Czy ktoś może podać link lub wyjaśnić, jak działa ten mechanizm buforowania? dzięki.
Sadok Mtir
2
Piękny i schludny!
Hatem Alimam
117

Obecnie, przy ES6, czuję, że moglibyśmy skorzystać ze zaktualizowanej odpowiedzi.

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

Zasadniczo (dla tych, którzy nie wiedzą), ponieważ onClickoczekuje, że funkcja zostanie do niej przekazana, binddziała, ponieważ tworzy kopię funkcji. Zamiast tego możemy przekazać wyrażenie funkcji strzałki, które po prostu wywołuje żądaną funkcję i zachowuje this. Nigdy nie powinieneś wiązać rendermetody w React, ale jeśli z jakiegoś powodu przegrywasz thisjedną z metod składowych:

constructor(props) {
  super(props);
  this.myMethod = this.myMethod.bind(this);
}
aikeru
źródło
10
Nigdy nie musisz wiązać, render()ponieważ jest wywoływany przez React. Jeśli już, potrzebujesz bindobsługi zdarzeń i tylko wtedy, gdy nie używasz strzałek.
Dan Abramov,
1
@ DanAbramov Myślę, że masz rację, ale załączyłem to na wszelki wypadek - zaktualizowano o przykład, który nie sugeruje domyślnie wiążącego renderowania.
aikeru
3
Zauważ, że to również najlepiej zdać propssię super()lub this.propszostanie undefined konstruktora, który może się okazać niejasna.
Dan Abramov
2
Co osiągnąć? Możesz zdefiniować moduł obsługi wewnątrz komponentu funkcjonalnego i przekazać go. Będzie to inna funkcja przy każdym renderowaniu, więc jeśli określiłeś za pomocą profilera, że ​​daje ci on problemy z perfem (i tylko jeśli naprawdę jesteś tego pewien!), Rozważ użycie klasy.
Dan Abramov,
1
@ me-me Tak, a jeśli zdecydujesz się na najnowocześniejszy JavaScript w Babel, powinieneś po prostu zadeklarować właściwości swojej klasy, takie jak, foo = () => {...}a następnie odwołać się w renderowaniu, <button onClick={this.foo}...jedynym powodem do włączenia funkcji strzałki, jeśli używasz Babel w ten sposób, IMO, jest, jeśli chcesz uchwycić jakąś zmienną, która istnieje tylko w zakresie metody render () (zdarzenia mogą być po prostu przekazywane i nie mają zastosowania).
aikeru
73

[[h / t do @ E.Sundin za linkowanie tego w komentarzu]

Najlepsza odpowiedź (funkcje anonimowe lub wiązanie) będzie działać, ale nie jest najbardziej wydajna, ponieważ tworzy kopię procedury obsługi zdarzeń dla każdej instancji wygenerowanej przez map()funkcję.

To jest wyjaśnienie optymalnego sposobu na zrobienie tego z wtyczki ESLint-reaguj :

Listy przedmiotów

Częstym przypadkiem użycia wiązania w renderowaniu jest renderowanie listy w celu oddzielnego wywołania zwrotnego dla każdego elementu listy:

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

Zamiast robić to w ten sposób, przeciągnij powtarzającą się sekcję do własnego komponentu:

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>
    );

});

Przyspieszy to renderowanie, ponieważ unika potrzeby tworzenia nowych funkcji (poprzez wywołania powiązań) na każdym renderowaniu.

Brandon
źródło
Czy reaguje na wywołanie tych funkcji za pomocą wywołania / zastosowania, a następnie pod maską i unika wewnętrznego łączenia?
aikeru
1
Czy można to zrobić za pomocą komponentu bezstanowego?
Carlos Martinez
2
@CarlosMartinez dobre oko, zaktualizowałem przykład - w pierwszej kolejności powinny to być bezpaństwowe komponenty funkcjonalne (SFC). Ogólnie rzecz biorąc, jeśli składnik nigdy nie używa this.state, możesz go bezpiecznie wymienić za pomocą SFC.
Brandon
3
Hmm, nie rozumiem, jak to jest bardziej wydajne? Nie będzie wywoływana funkcja ListItem za każdym razem, a zatem funkcja _onClick będzie tworzona przy każdym renderowaniu.
Mattias Petter Johansson
1
Nie jestem tutaj ekspertem, ale jak rozumiem, we „poprawnym” wzorze jest tylko jedna instancja modułu obsługi i przekazana jest prop dla dowolnej instancji komponentu, która ją wywoła. W przykładzie wiązania (tj. „Złym” wzorcu) istnieje jedna instancja modułu obsługi dla każdego utworzonego komponentu. Jest to rodzaj pamięciowego odpowiednika pisania tej samej funkcji trzydzieści razy na odwrót, pisząc ją raz i wywołując w razie potrzeby.
Brandon
25

To jest moje podejście, nie jestem pewien, jak źle jest, proszę o komentarz

W klikalnym elemencie

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

i wtedy

handleSort(e){
    this.sortOn(e.currentTarget.getAttribute('data-column'));
}
Santiago Ramirez
źródło
Jest to podejście, o którym myślałem, wydaje się nieco zuchwałe, ale unika tworzenia nowego komponentu. Nie jestem pewien, czy getAttribute jest lepszy czy gorszy w porównaniu z wciąganiem do osobnego komponentu.
kamranicus
2
Myślę, że to dobre rozwiązanie, ponieważ jest bardzo proste. Ale działa tylko z wartościami ciągów, jeśli chcesz obiekt, to nie działa.
Stephane L
Dla obiektu trzeba by zrobić encodeURIComponent(JSON.stringify(myObj)), to aby go analizować, JSON.parse(decodeURIComponent(myObj)). W przypadku funkcji jestem prawie pewien, że to nie zadziała bez eval lub nowej Function (), których należy unikać. Z tych powodów nie używam atrybutów danych do przekazywania danych w React / JS.
Solvitieg,
Chcę dodać, że nie używam tego często i tylko do drobnych rzeczy. Ale zwykle po prostu tworzę komponent i przekazuję mu dane jako rekwizyty. Następnie obsłuż kliknięcie wewnątrz tego nowego komponentu lub przekaż funkcję onClick do komponentu. Jak wyjaśniono w odpowiedzi Brandona
Santiago Ramirez
1
dostęp do zestawu danych można uzyskać bezpośrednio w ten sposób w nowoczesnych przeglądarkach (w tym IE11): e.currentTarget.dataset.column
gsziszi
17

ten przykład może się nieco różnić od twojego. ale zapewniam, że jest to najlepsze rozwiązanie tego problemu. szukałem dni od rozwiązania, które nie ma problemu z wydajnością. i wreszcie wymyślił ten.

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

AKTUALIZACJA

na przykład chcesz poradzić sobie z obiektami, które mają być parametrami. możesz użyć JSON.stringify(object)do przekonwertowania go na ciąg i dodania do zestawu danych.

return (
   <div>
     <h3 data-param={JSON.stringify({name:'me'})} onClick={this.handleClick}>
        {this.state.name}
     </h3>
   </div>
);
hannad rehman
źródło
1
to nie działa, gdy przekazywane dane są obiektem
SlimSim,
użyj JSON.stringify, aby rozwiązać problem. @SlimSim. to powinno
wystarczyć
Jeśli potrzebujesz użyć JSON.stringify dla tego problemu, to prawdopodobnie nie jest to poprawna metoda. Proces rygoryzacji zajmuje dużo pamięci.
KFE
w większości przypadków identyfikator podaje się tylko jako parametry, a szczegóły obiektu można uzyskać na podstawie tego identyfikatora z obiektu źródłowego. i dlaczego i jak to zajmuje dużo pamięci, wiem, że JSON stringify jest powolny, ale kliknięcie Fn jest asynchroniczne i nie będzie miało wpływu na dom, po zbudowaniu
hannad rehman
6
class extends React.Component {
    onClickDiv = (column) => {
        // do stuff
    }
    render() {
        return <div onClick={() => this.onClickDiv('123')} />
    }
}
Vladimirs Matusevics
źródło
2
To samo - nowy DOM na każdym renderowaniu. Więc React zaktualizuje DOM za każdym razem.
Alex Shwarc,
4

Jeszcze jedną opcją nie angażującą .bindani ES6 jest użycie komponentu potomnego z modułem obsługi do wywołania modułu nadrzędnego z niezbędnymi rekwizytami. Oto przykład (a link do działającego przykładu znajduje się poniżej):

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

Podstawową ideą jest przekazanie onClickfunkcji przez komponent nadrzędny do komponentu potomnego. Komponent potomny wywołuje onClickfunkcję i może uzyskiwać dostęp do wszystkich propsprzekazanych do niej (i event) elementów, umożliwiając użycie dowolnej eventwartości lub innych rekwizytów w obrębie elementu nadrzędnegoonClick .

Oto demo CodePen pokazujące tę metodę w akcji.

Brett DeWoody
źródło
4

Zdaję sobie sprawę, że impreza jest dość późna, ale myślę, że o wiele prostsze rozwiązanie może zaspokoić wiele przypadków użycia:

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

    ...

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

Zakładam, że możesz również użyć data- atrybutu.

Prosty, semantyczny.

jhchnc
źródło
4

Po prostu utwórz taką funkcję

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

i nazwij to w miejscu, którego potrzebujesz

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

Charith Jayasanka
źródło
3

Podejmowanie alternatywnej próby odpowiedzi na pytanie OP, w tym wywołań e.preventDefault ():

Renderowany link ( ES6 )

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

Funkcja elementu

handleSort = (e, param) => {
  e.preventDefault();
  console.log('Sorting by: ' + param)
}
Po Rith
źródło
3

Możesz po prostu to zrobić, jeśli używasz 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>
     );
   }
 }
Louis Alonzo
źródło
3

Wdrożenie pokazuje całkowitą liczbę z obiektu poprzez przekazanie licznika jako parametru z głównego do podskładników, jak opisano poniżej.

Oto 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;

I oto jest 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>
    )
  }
};

Spróbuj zaimplementować powyżej, a otrzymasz dokładny scenariusz, w którym parametry przekazywania działają w reakcjach dla dowolnej metody DOM.

nandu
źródło
3

Napisałem element opakowania, który można ponownie wykorzystać w tym celu, który opiera się na zaakceptowanych odpowiedziach tutaj. Jeśli wszystko, co musisz zrobić, to przekazać ciąg znaków, po prostu dodaj atrybut danych i przeczytaj go z e.target.dataset (jak sugerują niektórzy inni). Domyślnie mój wrapper wiąże się z dowolnym rekwizytem, ​​który jest funkcją i zaczyna się od „on” i automatycznie przekazuje rekwizyt danych z powrotem do programu wywołującego po wszystkich innych argumentach zdarzenia. Chociaż nie przetestowałem go pod kątem wydajności, da ci to możliwość uniknięcia samodzielnego tworzenia klasy i można go użyć w następujący sposób:

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

lub w przypadku komponentów i funkcji

const DataInput = withData(SomeComponent);

lub jeśli wolisz

const DataButton = withData(<button/>)

oświadcz, że poza kontenerem (w pobliżu importu)

Oto użycie w kontenerze:

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

Oto kod opakowania „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;
    }, {});
}
SlimSim
źródło
2

Mam poniżej 3 sugestii dotyczących tego zdarzenia w JSX onClick Events -

  1. W rzeczywistości nie musimy używać .bind () ani funkcji Arrow w naszym kodzie. Możesz w prosty sposób użyć w swoim kodzie.

  2. Możesz także przenieść zdarzenie onClick z th (lub ul) do tr (lub li), aby poprawić wydajność. Zasadniczo będziesz mieć n liczby „Detektorów zdarzeń” dla swojego elementu 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>

    // I można uzyskać dostęp item.idw onItemClicksposób, jak pokazano poniżej:

    onItemClick = (event) => {
       console.log(e.target.getAttribute("item.id"));
    }
  3. Zgadzam się z powyższym podejściem do tworzenia osobnego React Component dla ListItem i List. Sprawia to, że kod wygląda dobrze, ale jeśli masz 1000 li, to zostanie utworzonych 1000 detektorów zdarzeń. Upewnij się, że nie powinieneś mieć dużo detektora zdarzeń.

    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>
            );
        }
    }
Reetesh Agrawal
źródło
1
To nie działa, gdy dane, które musisz przekazać, są obiektem. Atrybut będzie działał tylko z łańcuchami. Również czytanie z domu za pomocą atrybutu get jest prawdopodobnie droższą operacją.
SlimSim,
2

Dodałem kod do przekazywania wartości zdarzenia onclick do metody na dwa sposoby. 1. przy użyciu metody powiązania 2. przy użyciu metody strzałki (=>). zobacz metody handlesort1 i 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>);
    }
});
Merugu Prashanth
źródło
2

Poniżej znajduje się przykład, który przekazuje wartość zdarzenia onClick.

Użyłem składni es6. zapamiętaj w klasie funkcja strzałki nie wiąże się automatycznie, więc jawnie wiąże się w konstruktorze.

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>
         );
    }
}
Karan Singh
źródło
2

Myślę, że będziesz musiał powiązać metodę z instancją klasy React. Bezpieczniej jest użyć konstruktora do powiązania wszystkich metod w React. W twoim przypadku, gdy przekazujesz parametr do metody, pierwszy parametr służy do powiązania kontekstu „this” metody, więc nie możesz uzyskać dostępu do wartości wewnątrz metody.

Andysenclave
źródło
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);
}
Juan David Arce
źródło
2

Jest to bardzo łatwy sposób.

 onClick={this.toggleStart('xyz')} . 
  toggleStart= (data) => (e) =>{
     console.log('value is'+data);  
 }
Roma Mukherjee
źródło
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>
    );
  }
}
Anik Mazumder
źródło
4
Chociaż ten kod może rozwiązać pytanie, to wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu.
Shree,
2

Wychodzę znikąd z tego pytania, ale myślę .bind, że zrobi to samo. Znajdź przykładowy kod poniżej.

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

<button onClick={handleClick.bind(null, { title: 'mytitle', id: '12345' })}>Login</button>
Charitha Goonewardena
źródło
1

Korzystanie z funkcji strzałki:

Musisz zainstalować etap 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; 
SM Chinna
źródło
0

Istnieją 3 sposoby, aby sobie z tym poradzić:

  1. Powiąż metodę w konstruktorze jako:

    export class HeaderRows extends Component {
       constructor() {
           super();
           this.handleSort = this.handleSort.bind(this);
       }
    }
  2. Użyj funkcji strzałki podczas tworzenia jej jako:

    handleSort = () => {
        // some text here
    }
  3. Trzeci sposób to:

    <th value={column} onClick={() => that.handleSort} >{column}</th>
Mansi Teharia
źródło
0

Możesz użyć swojego kodu w następujący sposób:

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

Tutaj jest dla obiektu zdarzenia, jeśli chcesz użyć metod zdarzenia, takich jak preventDefault()w funkcji uchwytu lub chcesz uzyskać wartość docelową lub nazwę jak e.target.name.

Bankim Sutaria
źródło
0

Znalazłem rozwiązanie przekazywania parametru param jako atrybutu tagu całkiem rozsądne.

Ma jednak ograniczenia:

  • Nie działa poprawnie, gdy element listy ma inne tagi (dlatego event.target może być inny niż zamierzony)
  • Param może być tylko ciągiem znaków. Wymaga serializacji i deserializacji.

Właśnie dlatego wymyśliłem tę bibliotekę: reaguj-zdarzenie-parametr

To:

  • Rozwiązuje problem dzieci, szukając w razie potrzeby potrzebnego atrybutu u rodziców
  • Automatycznie serializuje i deserializuje parametry
  • Zawiera logikę ustawiania i uzyskiwania. Nie musisz zadzierać z nazwami param

Przykład użycia:

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;
sneas
źródło
0

Było wiele kwestii związanych z wydajnością, wszystko w próżni.
Problem z tymi procedurami obsługi polega na tym, że musisz je curry, aby uwzględnić argument, którego nie można wymienić w rekwizytach.
Oznacza to, że komponent potrzebuje modułu obsługi dla każdego klikalnego elementu. Zgódźmy się, że dla kilku przycisków to nie jest problem, prawda?
Problem pojawia się podczas obsługi danych tabelarycznych z dziesiątkami kolumn i tysiącami wierszy. Tam zauważasz wpływ stworzenia tak wielu programów obsługi.

Faktem jest, że potrzebuję tylko jednego.
Ustawiam moduł obsługi na poziomie tabeli (lub UL lub OL ...), a po kliknięciu mogę stwierdzić, która komórka została kliknięta, używając danych dostępnych od zawsze w obiekcie zdarzenia:

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

Korzystam z pól zmiennych, aby sprawdzić, czy kliknięcie nastąpiło w prawidłowym elemencie, na przykład ignoruję kliknięcia w TH stopek.
RowIndex i cellIndex podają dokładną lokalizację klikniętej komórki.
Textcontent to tekst klikniętej komórki.

W ten sposób nie muszę przekazywać danych komórki do modułu obsługi, może to samoobsługi.
Jeśli potrzebuję więcej danych, danych, które nie mają być wyświetlane, mogę użyć atrybutu zestawu danych lub ukrytych elementów.
Z prostą nawigacją DOM wszystko jest pod ręką.
Jest to stosowane w HTML od zawsze, ponieważ komputery PC były znacznie łatwiejsze do bagna.

Juan Lanus
źródło
0

Istnieje kilka sposobów przekazywania parametrów w procedurach obsługi zdarzeń, niektóre są następujące.

Możesz użyć funkcji strzałki, aby owinąć moduł obsługi zdarzeń i przekazać parametry:

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

powyższy przykład jest równoważny z wywołaniem .bindlub możesz jawnie wywołać bind.

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

Oprócz tych dwóch podejść można także przekazywać argumenty do funkcji zdefiniowanej jako funkcja curry.

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

<button onClick={this.handleClick(id)} />
Umair Ahmed
źródło
-1

Użyj zamknięcia , aby uzyskać czyste rozwiązanie:

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

Funkcja handleSort zwróci funkcję, dla której kolumna wartości jest już ustawiona.

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

Funkcja anonimowa zostanie wywołana z poprawną wartością, gdy użytkownik kliknie th.

Przykład: https://stackblitz.com/edit/react-pass-parameters-example

Romel Gomez
źródło
-2

Wymagana prosta zmiana:

Posługiwać się <th value={column} onClick={that.handleSort} >{column}</th>

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

Al Amin Shaon
źródło