React JS обработчик событий onClick

120

у меня есть

var TestApp = React.createClass({
      getComponent: function(){
          console.log(this.props);
      },
      render: function(){
        return(
             <div>
             <ul>
                <li onClick={this.getComponent}>Component 1</li>
             </ul>
             </div>
        );
      }
});
React.renderComponent(<TestApp />, document.body);

Я хочу раскрасить фон элемента списка, по которому щелкнули мышью. Как я могу это сделать в React?

Что-то вроде

$('li').on('click', function(){
    $(this).css({'background-color': '#ccc'});
});
user544079
источник

Ответы:

95

Почему нет:

onItemClick: function (event) {

    event.currentTarget.style.backgroundColor = '#ccc';

},

render: function() {
    return (
        <div>
            <ul>
                <li onClick={this.onItemClick}>Component 1</li>
            </ul>
        </div>
    );
}

И если вы хотите быть более отзывчивым к этому, вы можете установить выбранный элемент как состояние содержащего его компонента React, а затем указать это состояние, чтобы определить цвет элемента внутри render:

onItemClick: function (event) {

    this.setState({ selectedItem: event.currentTarget.dataset.id });
    //where 'id' =  whatever suffix you give the data-* li attribute
},

render: function() {
    return (
        <div>
            <ul>
                <li onClick={this.onItemClick} data-id="1" className={this.state.selectedItem == 1 ? "on" : "off"}>Component 1</li>
                <li onClick={this.onItemClick} data-id="2" className={this.state.selectedItem == 2 ? "on" : "off"}>Component 2</li>
                <li onClick={this.onItemClick} data-id="3" className={this.state.selectedItem == 3 ? "on" : "off"}>Component 3</li>
            </ul>
        </div>
    );
},

Вы хотели бы поместить эти <li>S в петлю, и вы должны сделать li.onи li.offстили установить ваш background-color.

ericsoco
источник
Ручные манипуляции с DOM в React - это антипаттерн, который приводит только к большему количеству проблем. Избегайте таких вещей, как event.currentTarget.style.backgroundColor = '#ccc';если вы действительно не понимаете, что делаете (в большинстве случаев при интеграции сторонних виджетов).
Эмиль Бержерон
61

Я могу думать о двух способах:

var TestApp = React.createClass({
    getComponent: function(index) {
        $(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
            'background-color': '#ccc'
        });
    },
    render: function() {
        return (
            <div>
              <ul>
                <li onClick={this.getComponent.bind(this, 1)}>Component 1</li>
                <li onClick={this.getComponent.bind(this, 2)}>Component 2</li>
                <li onClick={this.getComponent.bind(this, 3)}>Component 3</li>
              </ul>
            </div>
        );
    }
});
React.renderComponent(<TestApp /> , document.getElementById('soln1'));

Это мой личный фаворит.

var ListItem = React.createClass({
    getInitialState: function() {
        return {
            isSelected: false
        };
    },
    handleClick: function() {
        this.setState({
            isSelected: true
        })
    },
    render: function() {
        var isSelected = this.state.isSelected;
        var style = {
            'background-color': ''
        };
        if (isSelected) {
            style = {
                'background-color': '#ccc'
            };
        }
        return (
            <li onClick={this.handleClick} style={style}>{this.props.content}</li>
        );
    }
});

var TestApp2 = React.createClass({
    getComponent: function(index) {
        $(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
            'background-color': '#ccc'
        });
    },
    render: function() {
        return (
            <div>
             <ul>
              <ListItem content="Component 1" />
              <ListItem content="Component 2" />
              <ListItem content="Component 3" />
             </ul>
            </div>
        );
    }
});
React.renderComponent(<TestApp2 /> , document.getElementById('soln2'));

Вот ДЕМО

Надеюсь, это поможет.

Dhiraj
источник
8
Не рекомендуется применять привязку внутри функции рендеринга, поскольку она будет делать это каждый раз при рендеринге компонента. вы можете переместить его в какую-нибудь функцию, которая запускается в начале жизненного цикла
jony89
1
@ jony89 согласился, если .bindне принимает дополнительный параметр. Но в первом случае это так. Я не думаю , что есть еще один способ
Dhiraj
1
Существует, создайте три разные функции (которые создаются результатом getComponent.bind (this, 1)), хотя это определенное может быть решением (сделало бы это для 2-3 компонентов, а не для 20 - если это действительно проблема производительности и легко создать его динамически).
jony89 01
38

Вот как вы определяете обработчик события onClick , который отвечал на заголовок вопроса ... с использованием синтаксиса es6

import React, { Component } from 'react';

export default class Test extends Component {
  handleClick(e) {
    e.preventDefault()
    console.log(e.target)
  }

  render() {
    return (
      <a href='#' onClick={e => this.handleClick(e)}>click me</a>
    )
  }
}
svnm
источник
9
Ни bindфункции, ни стрелочные функции не должны использоваться в renderметодах, потому что они приводят к созданию новой функции каждый раз. Это приводит к изменению состояния компонента, и компоненты с измененным состоянием всегда повторно визуализируются. Для сингла aэто не проблема. Для сгенерированных списков с интерактивными элементами это очень быстро становится проблемой. Вот почему это специально предостерегается.
hippietrail
18

Используйте ECMA2015. Стрелочные функции делают "это" намного более интуитивным.

import React from 'react';


class TestApp extends React.Component {
   getComponent(e, index) {
       $(e.target).css({
           'background-color': '#ccc'
       });
   }
   render() {
       return (
           <div>
             <ul>
               <li onClick={(e) => this.getComponent(e, 1)}>Component 1</li>
               <li onClick={(e) => this.getComponent(e, 2)}>Component 2</li>
               <li onClick={(e) => this.getComponent(e, 3)}>Component 3</li>
             </ul>
           </div>
       );
   }
});
React.renderComponent(<TestApp /> , document.getElementById('soln1'));`
itcropper
источник
2
indexздесь ничего не делает?
североамериканский
@northamerican - Нет, это просто для того, чтобы добавить ясности параметров
itcropper
5
На самом деле это плохо для производительности, так как создает новую функцию при каждом рендеринге. См .: stackoverflow.com/questions/36677733/…
Джочи Набуурс
1
И, пожалуйста, не используйте jQuery внутри React, если вам это не нужно!
Эмиль Бержерон
13

Если вы используете ES6, вот простой пример кода:

import React from 'wherever_react_is';

class TestApp extends React.Component {

  getComponent(event) {
      console.log('li item clicked!');
      event.currentTarget.style.backgroundColor = '#ccc';
  }

  render() {
    return(
       <div>
         <ul>
            <li onClick={this.getComponent.bind(this)}>Component 1</li>
         </ul>
       </div>
    );
  }
}

export default TestApp;

В телах классов ES6 функциям больше не требуется ключевое слово function, и их не нужно разделять запятыми. Вы также можете использовать синтаксис =>, если хотите.

Вот пример с динамически создаваемыми элементами:

import React from 'wherever_react_is';

class TestApp extends React.Component {

constructor(props) {
  super(props);

  this.state = {
    data: [
      {name: 'Name 1', id: 123},
      {name: 'Name 2', id: 456}
    ]
  }
}

  getComponent(event) {
      console.log('li item clicked!');
      event.currentTarget.style.backgroundColor = '#ccc';
  }

  render() {        
       <div>
         <ul>
         {this.state.data.map(d => {
           return(
              <li key={d.id} onClick={this.getComponent.bind(this)}>{d.name}</li>
           )}
         )}
         </ul>
       </div>
    );
  }
}

export default TestApp;

Обратите внимание, что каждый динамически создаваемый элемент должен иметь уникальный ссылочный «ключ».

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

Новая функция onClick:

getComponent(object) {
    console.log(object.name);
}

Передача объекта данных:

{this.state.data.map(d => {
    return(
      <li key={d.id} onClick={this.getComponent.bind(this, d)}>{d.name}</li>
    )}
)}
dirtigr00vz
источник
Я пытаюсь создать свои элементы li динамически, а затем это становится неопределенным, и поэтому функция onClick выдает ошибку.
приземлился
1
Я только что нашел аналогичный ответ, где вам нужно использовать .bind (this)); в конце анонимной функции, поскольку здесь это относится к окну до тех пор, пока вы не сделаете привязку ...
приземлился
6

Обработка событий с элементами React очень похожа на обработку событий в элементах DOM. Есть некоторые синтаксические отличия:

  • События React именуются с использованием camelCase, а не строчных букв.
  • В JSX в качестве обработчика событий передается функция, а не строка.

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

Посмотрите на пример ниже, обратите внимание на то, как событие передается в функцию:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}
Алиреза
источник
3

import React from 'react';

class MyComponent extends React.Component {

  getComponent(event) {
      event.target.style.backgroundColor = '#ccc';
      
      // or you can write
      //arguments[0].target.style.backgroundColor = '#ccc';
  }

  render() {
    return(
       <div>
         <ul>
            <li onClick={this.getComponent.bind(this)}>Component 1</li>
         </ul>
       </div>
    );
  }
}

export { MyComponent };  // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
export default MyComponent;

Джалаледдин Хоссейни
источник
Это кажется по существу идентичным ответу из 11 пунктов и воскрешает красивый - или вопрос - почему?
Дэйв Ньютон
2

class FrontendSkillList extends React.Component {
  constructor() {
    super();
    this.state = { selectedSkill: {} };
  }
  render() {
    return (
      <ul>
        {this.props.skills.map((skill, i) => (
            <li
              className={
                this.state.selectedSkill.id === skill.id ? "selected" : ""
              }
              onClick={this.selectSkill.bind(this, skill)}
              style={{ cursor: "pointer" }}
              key={skill.id}
            >
            {skill.name}
            </li>
        ))}
      </ul>
    );
  }

  selectSkill(selected) {
    if (selected.id !== this.state.selectedSkill.id) {
      this.setState({ selectedSkill: selected });
    } else {
      this.setState({ selectedSkill: {} });
    }
  }
}

const data = [
  { id: "1", name: "HTML5" },
  { id: "2", name: "CSS3" },
  { id: "3", name: "ES6 & ES7" }
];
const element = (
  <div>
    <h1>Frontend Skill List</h1>
    <FrontendSkillList skills={data} />
  </div>
);
ReactDOM.render(element, document.getElementById("root"));
.selected {
  background-color: rgba(217, 83, 79, 0.8);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

@ user544079 Надеюсь, эта демонстрация поможет :) Я рекомендую изменить цвет фона, переключив имя класса.

dabeng
источник
2

import React from 'react';

class MyComponent extends React.Component {

  getComponent(event) {
      event.target.style.backgroundColor = '#ccc';
      
      // or you can write
      //arguments[0].target.style.backgroundColor = '#ccc';
  }

  render() {
    return(
       <div>
         <ul>
            <li onClick={this.getComponent.bind(this)}>Component 1</li>
         </ul>
       </div>
    );
  }
}

export { MyComponent };  // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
export default MyComponent;

Jakkapan Sitthikan
источник
не могли бы вы предоставить больше контекста для этого кода, объяснив, как это может решить проблему?
МЕДЗ
1

Вы можете использовать метод React.createClone. Создайте свой элемент, затем создайте его клон. Во время создания клона вы можете вводить реквизит. Вставьте опору метода onClick: как это

{ onClick : () => this.changeColor(originalElement, index) }

метод changeColor установит состояние с дубликатом, что позволит вам установить цвет в процессе.

render()
  {
    return(
      <ul>

        {this.state.items.map((val, ind) => {
          let item = <li key={ind}>{val}</li>;
          let props = { 
            onClick: () => this.Click(item, ind),
            key : ind,
            ind
          }
          let clone = React.cloneElement(item, props, [val]);
          return clone;
        })}

      </ul>
    )
  }

Эдди Д.
источник
В клонировании нет необходимости.
Эмиль Бержерон
-17

Это нестандартный (но не такой уж и редкий) шаблон React, который не использует JSX, вместо этого помещает все в строку. Кроме того, это Coffeescript.

Реагировать на это можно с помощью собственного состояния компонента:

( c = console.log.bind console)

mock_items: [
    {
        name: 'item_a'
        uid: shortid()
    }
    {
        name: 'item_b'
        uid: shortid()
    }
    {
        name: 'item_c'
        uid: shortid()
    }
]
getInitialState: ->
    lighted_item: null
render: ->
    div null,
        ul null,
            for item, idx in @mock_items
                uid = item.uid
                li
                    key: uid
                    onClick: do (idx, uid) =>
                        (e) =>
                            # justf to illustrate these are bound in closure by the do lambda,
                            c idx
                            c uid
                            @setState
                                lighted_item: uid
                    style:
                        cursor: 'pointer'
                        background: do (uid) =>
                            c @state.lighted_item
                            c 'and uid', uid
                            if @state.lighted_item is uid then 'magenta' else 'chartreuse'
                        # background: 'chartreuse'
                    item.name

Этот пример работает - я тестировал его локально. Вы можете посмотреть этот пример кода в моем гитхабе . Первоначально env был локальным только для моих собственных научно-исследовательских целей, но для этого я разместил его на Github. В какой-то момент он может быть переписан, но вы можете проверить фиксацию от 8 сентября 2016 года, чтобы убедиться в этом.

В более общем плане, если вы хотите увидеть, как работает этот шаблон CS / no-JSX для React, ознакомьтесь с некоторыми недавними работами здесь . Возможно, у меня будет время полностью реализовать POC для этой идеи приложения, стек для которого включает NodeJS, Primus, Redis и React.

Вайли Кулик
источник
фон не обязательно должен быть doлямбда: Это выражение также работает:background: if @state.lighted_item is uid then 'magenta' else 'chartreuse'
Wylie Kulik
привет, как я могу просмотреть onclick в консоли браузера?
Muneem Habib
12
Зачем вам использовать CoffeeScript в ответе на вопрос, в котором он никоим образом не упоминается? В этом нет никакого смысла, и это, вероятно, может затруднить чтение ответа для спрашивающего, поскольку он может не знать / не любить CoffeeScript. Очевидно, голосование против.
macbem 07
7
Нет, но это что-то построенное на основе языка, не является стандартным и требует установки и компиляции. было действительно плохим выбором написать свой ответ на coffeescript, когда НУЛЬ намекает на то, что они используют coffeescript в своем проекте
TheRealMrCrowley
4
Coffeescript - это просто слой поверх js. FTFY.
machineghost