Trình xử lý sự kiện trên React JS onClick


120

Tôi có

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

Tôi muốn tô màu nền của phần tử danh sách được nhấp. Làm cách nào để làm điều này trong React?

Cái gì đó như

$('li').on('click', function(){
    $(this).css({'background-color': '#ccc'});
});

Câu trả lời:


95

Tại sao không:

onItemClick: function (event) {

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

},

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

Và nếu bạn muốn hiểu rõ hơn về React-ive về nó, bạn có thể muốn đặt mục đã chọn làm trạng thái của thành phần React chứa nó, sau đó tham chiếu trạng thái đó để xác định màu của mục trong 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>
    );
},

Bạn muốn đặt những thứ đó <li>vào một vòng lặp, và bạn cần đặt kiểu li.onli.offkiểu của mình background-color.


Thao tác DOM thủ công trong React là một mô hình chống lại điều này chỉ dẫn đến nhiều vấn đề hơn. Tránh những thứ như event.currentTarget.style.backgroundColor = '#ccc';trừ khi bạn thực sự hiểu những gì bạn đang làm (hầu hết các trường hợp, trong khi tích hợp các tiện ích của bên thứ ba).
Emile Bergeron

61

Hai cách tôi có thể nghĩ ra là

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

Đây là yêu thích cá nhân của tôi.

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

Đây là một DEMO

Tôi hi vọng cái này giúp được.


8
Bạn không nên áp dụng ràng buộc trong hàm kết xuất vì nó sẽ thực hiện nó mỗi khi thành phần được hiển thị. bạn có thể di chuyển nó đến một số chức năng mà chạy vào lúc bắt đầu của vòng đời
jony89

1
@ jony89 đồng ý nếu .bindkhông có tham số phụ. Nhưng trong trường hợp đầu tiên thì có. Tôi không nghĩ rằng có một cách khác
Dhiraj

1
Có, tạo ba hàm khác nhau (được tạo bởi kết quả của getComponent.bind (this, 1)), mặc dù định nghĩa đó có thể là một quyết định (sẽ làm điều đó cho 2-3 thành phần, không phải cho 20 - trừ khi nó thực sự là vấn đề về hiệu suất và dễ dàng tạo động).
jony89

38

Đây là cách bạn xác định một trình xử lý sự kiện react onClick , đang trả lời tiêu đề câu hỏi ... bằng cú pháp 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
Không bindnên sử dụng cả hàm hoặc hàm mũi tên trong rendercác phương thức vì chúng dẫn đến một hàm mới được tạo mỗi lần. Điều này có tác dụng thay đổi trạng thái của thành phần và các thành phần có trạng thái đã thay đổi luôn được hiển thị lại. Đối với một người duy nhất, ađây không phải là vấn đề lớn. Đối với danh sách được tạo với các mục có thể nhấp, điều này trở thành một vấn đề lớn rất nhanh chóng. Đây là lý do tại sao nó được cảnh báo đặc biệt.
hippietrail

18

Sử dụng ECMA2015. Các hàm mũi tên làm cho "cái này" trực quan hơn rất nhiều.

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
indexkhông làm gì ở đây?
Northamerican

@northamerican - Không, nó chỉ có thêm một số thông số rõ ràng
itcropper

5
Điều này thực sự không tốt cho hiệu suất vì nó tạo ra một chức năng mới sau mỗi lần hiển thị. Xem: stackoverflow.com/questions/36677733/...
Jochie Nabuurs

1
Và vui lòng không sử dụng jQuery bên trong React nếu bạn không cần thiết!
Emile Bergeron

13

Nếu bạn đang sử dụng ES6, đây là một số mã ví dụ đơn giản:

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;

Trong các phần thân của lớp ES6, các hàm không còn yêu cầu từ khóa 'function' và chúng không cần được phân tách bằng dấu phẩy. Bạn cũng có thể sử dụng cú pháp => nếu muốn.

Dưới đây là một ví dụ với các phần tử được tạo động:

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;

Lưu ý rằng mỗi phần tử được tạo động phải có một 'khóa' tham chiếu duy nhất.

Hơn nữa, nếu bạn muốn chuyển đối tượng dữ liệu thực tế (thay vì sự kiện) vào hàm onClick của mình, bạn sẽ cần chuyển đối tượng đó vào ràng buộc của mình. Ví dụ:

Chức năng onClick mới:

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

Truyền vào đối tượng dữ liệu:

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

Tôi đang cố gắng xây dựng các mục li của mình động và sau đó điều này trở thành không xác định và do đó hàm onClick gặp lỗi.
hạ cánh

1
Tôi vừa tìm thấy một câu trả lời tương tự khi bạn cần sử dụng .bind (this)); ở cuối hàm ẩn danh vì điều này ở đây đề cập đến cửa sổ cho đến khi bạn thực hiện ràng buộc ...
đã hạ cánh vào


6

Việc xử lý các sự kiện với các phần tử React rất giống với việc xử lý các sự kiện trên các phần tử DOM. Có một số khác biệt về cú pháp:

  • Các sự kiện React được đặt tên bằng camelCase, thay vì chữ thường.
  • Với JSX, bạn chuyển một hàm làm trình xử lý sự kiện, thay vì một chuỗi.

Vì vậy, như đã đề cập trong React tài liệu , chúng khá giống với HTML bình thường khi nói đến Xử lý sự kiện, nhưng tên sự kiện trong React sử dụng camelcase, bởi vì chúng không thực sự là HTML, chúng là JavaScript, bạn truyền hàm trong khi chúng ta chuyển lệnh gọi hàm ở định dạng chuỗi cho HTML, chúng khác nhau, nhưng các khái niệm khá giống nhau ...

Hãy xem ví dụ bên dưới, chú ý đến cách sự kiện được truyền vào hàm:

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;


Điều này về cơ bản có vẻ giống với câu trả lời 11 điểm, và làm sống lại một câu hỏi-hay-tại sao?
Dave Newton

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 Hy vọng bản demo này có thể giúp ích :) Tôi khuyên bạn nên thay đổi màu nền bằng cách chuyển đổi tên lớp.


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;


bạn có thể cung cấp thêm ngữ cảnh cho mã này bằng cách giải thích cách điều này có thể khắc phục sự cố không?
MEDZ

1

Bạn có thể sử dụng phương thức React.createClone. Tạo phần tử của bạn, hơn là tạo một bản sao của nó. Trong quá trình tạo bản sao, bạn có thể tiêm đạo cụ. Chèn một phương thức onClick: như thế này

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

phương thức changeColor sẽ thiết lập trạng thái với bản sao, cho phép bạn thiết lập màu trong quá trình này.

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


Nhân bản là hoàn toàn không cần thiết.
Emile Bergeron

-17

Đây là một mẫu React không chuẩn (nhưng không quá phổ biến) không sử dụng JSX, thay vào đó đưa mọi thứ vào nội tuyến. Ngoài ra, đó là Coffeescript.

'React-way' để làm điều này sẽ là với trạng thái riêng của thành phần:

( 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

Ví dụ này hoạt động - Tôi đã thử nghiệm nó cục bộ. Bạn có thể kiểm tra chính xác mã ví dụ này tại github của tôi . Ban đầu env chỉ là cục bộ cho mục đích r & d bảng trắng của riêng tôi nhưng tôi đã đăng nó lên Github cho mục đích này. Nó có thể được viết xong vào một lúc nào đó nhưng bạn có thể xem cam kết từ ngày 8 tháng 9 năm 2016 để xem điều này.

Nói chung hơn, nếu bạn muốn xem mẫu CS / no-JSX này cho React hoạt động như thế nào, hãy xem một số công việc gần đây tại đây . Có thể tôi sẽ có thời gian để triển khai đầy đủ POC cho ý tưởng ứng dụng này, ngăn xếp bao gồm NodeJS, Primus, Redis và React.


nền không cần phải là một dolambda: biểu hiện này hoạt động cũng:background: if @state.lighted_item is uid then 'magenta' else 'chartreuse'
Wylie Kulik

xin chào làm cách nào để tôi có thể xem onclick trên bảng điều khiển trình duyệt?
Muneem Habib

12
Tại sao bạn lại sử dụng CoffeeScript trong câu trả lời cho một câu hỏi không đề cập đến nó theo bất kỳ cách nào? Nó không có ý nghĩa gì và nó có thể làm cho người hỏi khó đọc câu trả lời hơn, vì anh ta có thể không biết / thích CoffeeScript. Từ chối, rõ ràng.
macbem

7
Không nhưng nó là thứ được xây dựng dựa trên ngôn ngữ, hoàn toàn không phải là tiêu chuẩn và yêu cầu cài đặt và biên dịch. đó là một thực sự là một sự lựa chọn nghèo để viết câu trả lời của bạn trong coffeescript khi có ZERO gián tiếp ở tất cả những gì họ đang sử dụng coffeescript trong dự án của họ
TheRealMrCrowley

4
Coffeescript chỉ là một lớp trên đầu trang của js. FTFY.
machineghost
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.