React js onClick не может передать значение методу


639

Я хочу прочитать свойства значения события onClick. Но когда я нажимаю на нее, я вижу что-то вроде этого на консоли:

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

Мой код работает правильно. Когда я бегу, я вижу, {column}но не могу получить его в событии onClick.

Мой код:

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

Как передать значение onClickсобытию в React js?



2
рассмотрите использование себя вместо этого. Это вводит в заблуждение, поскольку оно должно быть синонимом слова «это» (хотя на самом деле это не важно, каждому свое)
Дан,

Используя метод связывания и метод стрелки, мы можем передать значение событию
Onclick

Ответы:


1287

Простой способ

Используйте функцию стрелки:

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

Это создаст новую функцию, которая вызывает handleSort с правильными параметрами.

Лучший путь

Извлеките его в подкомпонент. Проблема с использованием функции стрелки в вызове рендеринга заключается в том, что она каждый раз создает новую функцию, которая в итоге вызывает ненужные повторные рендеринг.

Если вы создаете подкомпонент, вы можете передать обработчик и использовать реквизиты в качестве аргументов, которые затем будут перерисовываться только при изменении реквизитов (потому что ссылка на обработчик теперь никогда не меняется):

Субкомпонент

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

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

Главный компонент

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

Старый легкий путь (ES5)

Используйте .bindдля передачи желаемого параметра:

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

7
Реакция дает предупреждение, когда я использую как ваш код. Я изменяю свой код на onClick = {that.onClick.bind (null, column)}
user1924375

12
Как бы вы использовали это с <a>тегом, где вам нужно передать событие, чтобы использоватьpreventDefault()
Simon H

38
@SimonH Событие будет передано в качестве последнего аргумента после аргументов, которые вы передаете bind.
пятно

47
Разве это не плохо для производительности? новая функция будет создана на каждом рендере?
AndrewMcLagan

13
@ AndrewMcLagan Это так. Я нашел это, чтобы описать правило и наиболее эффективное решение.
Е. Сундин

140

Здесь есть хорошие ответы, и я согласен с @Austin Greco (второй вариант с отдельными компонентами).
Есть еще один способ, который мне нравится - карри .
Что вы можете сделать, это создать функцию, которая принимает параметр (ваш параметр) и возвращает другую функцию, которая принимает другой параметр (в данном случае событие click). тогда вы можете делать с ним все, что захотите.

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

И вы будете использовать это так:

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

Вот полный пример такого использования:

Обратите внимание, что этот подход не решает создание нового экземпляра на каждом рендере.
Мне нравится этот подход по сравнению с другими встроенными обработчиками, так как этот, на мой взгляд, более лаконичен и читабелен.

Редактировать:
как предлагается в комментариях ниже, вы можете кэшировать / запоминать результат функции.

Вот наивная реализация:


12
Это должен быть принятый ответ. ДЕЙСТВИТЕЛЬНО прост в реализации, и вам не нужно создавать какие-либо другие компоненты или связывать по-другому. Спасибо!
Tamb

29
Выглядит лучше, но с точки зрения производительности карри не очень помогает, потому что, если вы дважды вызываете handleChange с одним и тем же параметром, вы получаете две функции, которые механизм JS считает отдельными объектами, даже если они делают одно и то же , Таким образом, вы все еще получаете повторную визуализацию. Для повышения производительности вам необходимо будет кэшировать результаты handleChange, чтобы получить преимущество в производительности. LikehandleChange = param => cache[param] || (e => { // the function body })
travelllingprog

6
Это идеальный ответ, если вы выполните совет от @travellingprog
llioor

2
Кто-нибудь может предоставить ссылку или объяснить, как работает этот механизм кэширования? Спасибо.
Садок Мтир

2
Красиво и аккуратно!
Хатем Алимам,

117

В настоящее время, с ES6, я чувствую, что мы могли бы использовать обновленный ответ.

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

По сути, (для тех, кто не знает), поскольку onClickожидает, что ему передана функция, bindработает, потому что он создает копию функции. Вместо этого мы можем передать выражение функции стрелки, которое просто вызывает функцию, которую мы хотим, и сохраняет this. Вам никогда не нужно связывать renderметод в React, но если по какой-то причине вы проигрываете thisв одном из ваших компонентных методов:

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

10
Вам никогда не нужно связывать, render()потому что это называется React. Во всяком случае, вам нужны bindобработчики событий, и только тогда, когда вы не используете стрелки.
Дан Абрамов

1
@DanAbramov Я думаю, что вы правы, но я включил это на всякий случай - обновил пример, который не поощряет рендеринг связывания.
aikeru

3
Обратите внимание , что это также лучше , чтобы перейти propsк super()или this.propsбудет определено во время конструктора , который может привести к путанице.
Дан Абрамов

2
Чтобы достичь чего? Вы можете определить обработчик внутри функционального компонента и передать его. Это будет отличная функция при каждом рендеринге, поэтому, если вы определили с профилировщиком, что он вызывает проблемы с перфорированием (и только если вы действительно уверены в этом!), Рассмотрите возможность использования класса.
Дан Абрамов

1
@ me-me Да, и если вы включите новейший JavaScript в Babel, вы должны просто объявить свойства вашего класса как, foo = () => {...}а затем указать в render <button onClick={this.foo}...единственную причину, чтобы включить функцию стрелки, если вы так используете babel, IMO, если вы хотите захватить некоторую переменную, которая существует только в области видимости метода render () (события могут просто передаваться и не применяться).
aikeru

73

[[h / t к @ E.Sundin для того, чтобы связать это в комментарии]

Верхний ответ (анонимные функции или привязка) будет работать, но он не самый производительный, поскольку он создает копию обработчика событий для каждого экземпляра, сгенерированного map()функцией.

Это объяснение оптимального способа сделать это из ESLint-plugin-реакции :

Списки предметов

Обычный случай использования связывания при рендеринге - при рендеринге списка, чтобы иметь отдельный обратный вызов для каждого элемента списка:

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

Вместо того, чтобы делать это таким образом, перетащите повторяющийся раздел в его собственный компонент:

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

});

Это ускорит рендеринг, поскольку избавляет от необходимости создавать новые функции (посредством вызовов связывания) при каждом рендеринге.


Вызывает ли реакция те функции с помощью call / apply, затем скрытно и избегает внутреннего связывания?
aikeru

1
Есть ли способ сделать это с помощью компонента без состояния?
Карлос Мартинес

2
@CarlosMartinez хороший глаз, я обновил пример - они должны были быть функциональными компонентами без сохранения состояния (SFC). Как правило, если компонент никогда не используется this.state, вы можете смело менять его с помощью SFC.
Брэндон

3
Хм, я не понимаю, как это более производительно? Не будет ли функция ListItem вызываться каждый раз, и, таким образом, функция _onClick будет создаваться при каждом рендеринге.
Маттиас Петтер Йоханссон

1
Я здесь далеко не эксперт, но, насколько я понимаю, в «правильном» шаблоне есть только один экземпляр обработчика, и он пропущен для любого экземпляра компонента, который его вызывает. В примере связывания (т. Е. «Неправильный» шаблон) есть один экземпляр обработчика для каждого созданного экземпляра компонента. Это своего рода эквивалент памяти написания одной и той же функции тридцать раз, вместо того, чтобы писать ее один раз и вызывать ее по мере необходимости.
Брэндон

25

Это мой подход, не уверен, насколько это плохо, пожалуйста, прокомментируйте

В кликабельном элементе

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

а потом

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

Я думал об этом подходе, он немного хакерский, но избегает создания нового компонента. Я не уверен, что getAttribute лучше или хуже в сравнении с отдельным компонентом.
kamranicus

2
Я думаю, что это хорошее решение, потому что это очень просто. Но он работает только со строковыми значениями, если вам нужен объект, он не работает.
Стефан Л

Для объекта, который вам нужно сделать encodeURIComponent(JSON.stringify(myObj)), затем проанализировать его JSON.parse(decodeURIComponent(myObj)). Для функций я уверен, что это не будет работать без eval или новой функции (), чего следует избегать. По этим причинам я не использую атрибуты данных для передачи данных в React / JS.
Solvitieg

Я хочу добавить, что я не использую это часто и только для незначительных вещей. Но обычно я просто создаю компонент и передаю данные как реквизиты. Затем либо обработайте щелчок внутри этого нового компонента, либо передайте ему функцию onClick. Как поясняется в ответе Брэндона
Сантьяго Рамирес

1
Доступ к набору данных можно получить напрямую в современных браузерах (включая IE11): e.currentTarget.dataset.column
gsziszi

17

этот пример может немного отличаться от вашего. но я могу заверить вас, что это лучшее решение для этой проблемы. Я искал несколько дней решение, которое не имеет проблемы с производительностью. и, наконец, придумал это.

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

ОБНОВИТЬ

если вы хотите иметь дело с объектами, которые должны быть параметрами. Вы можете использовать, JSON.stringify(object)чтобы преобразовать его в строку и добавить в набор данных.

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

1
это не работает, когда переданные данные являются объектом
SlimSim

используйте JSON.stringify, чтобы исправить проблему. @SlimSim. это должно
сработать

Если вам нужно использовать JSON.stringify для этой проблемы, то, вероятно, это не правильный метод. Процесс строкового преобразования занимает много памяти.
KFE

в большинстве случаев вы просто передаете ID в качестве параметров и получаете сведения об объекте на основе этого идентификатора из исходного объекта. и почему и как это занимает много памяти, я знаю, что JSON stringify работает медленно, но щелчок Fn является асинхронным, и он не будет иметь никакого эффекта или 0 для dom, как только он будет
создан


4

Еще одна опция, не включающая .bindили не использующая ES6, - это использование дочернего компонента с обработчиком для вызова родительского обработчика с необходимыми реквизитами. Вот пример (и ссылка на рабочий пример ниже):

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

Основная идея заключается в том, чтобы родительский компонент передавал onClickфункцию дочернему компоненту. Дочерний компонент вызывает onClickфункцию и может получить доступ к любому propsпереданному ей (и event), что позволяет вам использовать любое eventзначение или другие реквизиты внутри родительского элемента.onClick .

Вот демонстрация CodePen, демонстрирующая этот метод в действии.


4

Попытка ответить на вопрос OP, включая вызовы e.preventDefault ():

Предоставленная ссылка ( ES6 )

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

Функция компонента

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

4

Я понимаю, что это довольно поздно для вечеринки, но я думаю, что гораздо более простое решение может удовлетворить многие варианты использования:

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

    ...

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

Я полагаю, вы также можете использовать data-атрибут.

Простой, семантический.


4

Просто создайте такую ​​функцию

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

и позвоните в нужное вам место

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


3

Вы можете просто сделать это, если вы используете 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

Реализация показа общего количества от объекта путем передачи количества в качестве параметра от основного к вспомогательным компонентам, как описано ниже.

Вот 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;

А вот 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>
    )
  }
};

Попробуйте реализовать выше, и вы получите точный сценарий того, как параметры передачи работают вactjs для любого метода DOM.


3

Я написал компонент-обертку, который можно использовать повторно для этой цели, основываясь на принятых здесь ответах. Если все, что вам нужно сделать, это передать строку, однако, просто добавьте атрибут data и прочитайте его из e.target.dataset (как предлагали некоторые другие). По умолчанию моя обертка будет связываться с любым реквизитом, который является функцией, и начинается с 'on' и автоматически передает реквизит данных вызывающей стороне после всех других аргументов события. Хотя я не проверял его на производительность, он даст вам возможность избежать создания класса самостоятельно, и его можно использовать так:

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

или для компонентов и функций

const DataInput = withData(SomeComponent);

или если вы предпочитаете

const DataButton = withData(<button/>)

заявить, что за пределами вашего контейнера (около вашего импорта)

Вот использование в контейнере:

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

Вот код оболочки '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

У меня есть ниже 3 предложения на это на JSX onClick Events -

  1. На самом деле нам не нужно использовать функцию .bind () или Arrow в нашем коде. Вы можете просто использовать в своем коде.

  2. Вы также можете переместить событие onClick из th (или ul) в tr (или li), чтобы повысить производительность. В основном у вас будет n «прослушивателей событий» для вашего элемента 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>

    // И вы можете получить доступ item.idк onItemClickметоду, как показано ниже:

    onItemClick = (event) => {
       console.log(e.target.getAttribute("item.id"));
    }
  3. Я согласен с упомянутым выше подходом к созданию отдельных компонентов React для ListItem и List. Этот код выглядит хорошо, однако, если у вас есть 1000 li, то будет создано 1000 прослушивателей событий. Пожалуйста, убедитесь, что у вас не так много слушателей событий.

    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
Это не работает, когда данные, которые вам нужно передать, являются объектом. Атрибут будет работать только со строками. Также чтение из dom через атрибут get, вероятно, является более дорогой операцией.
SlimSim

2

Я добавил код для передачи значения события onclick в метод двумя способами. 1 используя метод связывания 2. используя метод стрелки (=>). см. методы handlesort1 и 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

Ниже приведен пример, который передает значение на событие onClick.

Я использовал синтаксис es6. Помните, что в компоненте класса стрелка функция не связывается автоматически, поэтому явно связывается в конструкторе.

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

Я предполагаю, что вам придется привязать метод к экземпляру класса React. Безопаснее использовать конструктор для связывания всех методов в React. В вашем случае, когда вы передаете параметр методу, первый параметр используется для привязки контекста метода «this», поэтому вы не можете получить доступ к значению внутри метода.


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
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
Хотя этот код может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего поста. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.
Шри

2

Выход из ниоткуда на этот вопрос, но я думаю, что .bindдобьется цели. Найдите пример кода ниже.

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

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

1

Используя функцию стрелки:

Вы должны установить этап 2:

npm установить 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

Есть 3 способа справиться с этим:

  1. Привязать метод в конструкторе как: -

    export class HeaderRows extends Component {
       constructor() {
           super();
           this.handleSort = this.handleSort.bind(this);
       }
    }
  2. Используйте функцию стрелки, создавая ее как: -

    handleSort = () => {
        // some text here
    }
  3. Третий способ заключается в следующем:

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

0

Вы можете использовать свой код следующим образом:

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

Здесь e для объекта события, если вы хотите использовать методы события, как preventDefault()в вашей функции handle, или хотите получить целевое значение или имя как e.target.name.


0

Я нашел решение передачи param в качестве атрибута тега довольно разумным.

Однако у него есть ограничения:

  • Не работает должным образом, когда элемент списка имеет другие теги (таким образом, event.target может отличаться от запланированного)
  • Param может быть только строкой. Требуется сериализация и десериализация.

Вот почему я придумал эту библиотеку: Reaction-Event-Param

Это:

  • Решает проблему детей путем поиска нужного атрибута у родителей при необходимости
  • Автоматически сериализует и десериализует param
  • Инкапсулирует логику установки и получения. Не нужно связываться с именами параметров

Пример использования:

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

Было много соображений производительности, все в вакууме.
Проблема с этими обработчиками заключается в том, что вам нужно их карри, чтобы включить аргумент, который вы не можете назвать в реквизитах.
Это означает, что компоненту нужен обработчик для каждого кликабельного элемента. Давайте согласимся, что для нескольких кнопок это не проблема, верно?
Проблема возникает, когда вы обрабатываете табличные данные с десятками столбцов и тысячами строк. Там вы заметили влияние создания такого количества обработчиков.

Дело в том, что мне нужен только один.
Я устанавливаю обработчик на уровне таблицы (или UL или OL ...), и когда происходит щелчок, я могу определить, какая ячейка была нажата, используя данные, доступные с тех пор в объекте события:

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

Я использую поля тэгов, чтобы проверить, что щелчок произошел в допустимом элементе, например, игнорировать щелчки в нижних колонтитулах.
RowIndex и cellIndex дают точное местоположение нажатой ячейки.
Textcontent - это текст ячейки, по которой щелкнули.

Таким образом, мне не нужно передавать данные ячейки обработчику, он может самообслуживаться.
Если мне нужно больше данных, данных, которые не должны отображаться, я могу использовать атрибут набора данных или скрытые элементы.
С простой навигацией по DOM все под рукой.
Это используется в HTML с тех пор, как ПК было намного проще.


0

Есть несколько способов передать параметр в обработчиках событий, некоторые из них следующие.

Вы можете использовать функцию стрелки, чтобы обернуть вокруг обработчик события и передать параметры:

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

Приведенный выше пример эквивалентен вызову .bindили вы можете явно вызвать bind.

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

Помимо этих двух подходов, вы также можете передавать аргументы в функцию, которая определена как функция карри.

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

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

-1

Используйте закрытие , это приведет к чистому решению:

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

Функция handleSort вернет функцию с уже установленным столбцом значений .

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

Анонимная функция будет вызываться с правильным значением, когда пользователь нажимает кнопку th.

Пример: https://stackblitz.com/edit/react-pass-parameters-example


-2

Простое изменение требуется:

использование <th value={column} onClick={that.handleSort} >{column}</th>

вместо <th value={column} onClick={that.handleSort} >{column}</th>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.