Реагуйте на обробку подій 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'});
});

Відповіді:


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.


Ручна маніпуляція з 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'));

Ось DEMO

Я сподіваюся, що це допомагає.


8
Не рекомендується застосовувати прив'язку у функції візуалізації, оскільки це буде робити це кожного разу, коли компонент буде наданий. ви можете перемістити його на деяку функцію, яка працює на початку життєвого циклу
jony89

1
@ jony89 погодився, якщо .bindне приймає зайвий параметр. Але в першому випадку це так. Я не думаю, що є інший спосіб
Dhiraj

1
Є, створіть три різні функції (які створені результатом getComponent.bind (це, 1)), хоча це визначене може бути рішенням (було б це зробити для 2-3 компонентів, а не для 20 - якщо це не справді проблема з продуктивністю і легко створити його динамічно).
jony89

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

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

2
indexтут нічого не роблять?
північноамериканський

@northamerican - Ні, це просто там, щоб додати трохи ясності параметрів
itcropper

5
Це насправді погано для продуктивності, оскільки створює нову функцію при кожному візуалізації. Див: stackoverflow.com/questions/36677733 / ...
Jochie Nabuurs

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 функції більше не потребують ключового слова "функція", і їх не потрібно розділяти комами. Ви також можете використовувати синтаксис =>, якщо хочете.

Ось приклад з динамічно створеними елементами:

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

Я намагаюся створити свої елементи li динамічними, а потім це стає невизначеним, тому функція onClick видає помилку.
приземлився

1
Я щойно знайшов подібну відповідь, де потрібно використовувати .bind (this)); наприкінці анонімної функції, оскільки це стосується вікна, поки ви не зробите прив'язку ...
приземлився


6

Обробка подій за допомогою елементів React дуже схожа на обробку подій на елементах DOM. Є деякі синтаксичні відмінності:

  • Події реагування називаються за допомогою 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 Сподіваюся, що ця демонстрація може допомогти :) Я рекомендую змінити колір тла шляхом змінення назви класу.


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;


чи можете ви надати більше контексту цього коду, пояснивши, як це могло б вирішити проблему?
МЕДЗ

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

Цей приклад працює - я тестував його локально. Ви можете перевірити цей приклад код саме в моїй github . Спочатку 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'
Вілі Кулік

привіт, як я можу переглянути onclick на консолі браузера?
Muneem Habib

12
Чому б ви використовували CoffeeScript у відповіді на питання, яке ні в якому разі не згадує? Це не має ніякого сенсу, і, ймовірно, може зробити відповідь важче прочитати запитувачу, оскільки він може не знати / любити CoffeeScript. Очевидно.
macbem

7
Ні, але це щось, побудоване на мові, абсолютно не є стандартним і вимагає встановлення та компіляції. це було по-справжньому поганим вибором написати свою відповідь в coffeescript, коли ZERO натякає на те, що вони використовують coffeescript у своєму проекті
TheRealMrCrowley

4
Coffeescript - це лише шар поверх js. FTFY.
machineghost
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.