React JS onClick event handler


120

saya sudah

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

Saya ingin mewarnai latar belakang elemen daftar yang diklik. Bagaimana saya bisa melakukan ini di React?

Sesuatu seperti

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

Jawaban:


95

Kenapa tidak:

onItemClick: function (event) {

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

},

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

Dan jika Anda ingin menjadi lebih React-ive tentangnya, Anda mungkin ingin mengatur item yang dipilih sebagai status yang mengandung komponen React, kemudian merujuk status itu untuk menentukan warna item di dalamnya 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>
    );
},

Anda ingin memasukkannya <li>ke dalam satu lingkaran, dan Anda perlu mengatur gaya li.ondan .li.offbackground-color


Manipulasi DOM manual di React adalah anti-pola yang hanya menyebabkan lebih banyak masalah. Hindari hal-hal seperti event.currentTarget.style.backgroundColor = '#ccc';kecuali jika Anda benar-benar memahami apa yang Anda lakukan (sebagian besar waktu, saat mengintegrasikan widget pihak ketiga).
Emile Bergeron

61

Dua cara yang bisa saya pikirkan adalah

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

Ini adalah favorit pribadi saya.

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

Berikut adalah DEMO

Saya harap ini membantu.


8
Tidak disarankan untuk menerapkan bind dalam fungsi render karena ini akan melakukannya setiap kali komponen dirender. Anda dapat memindahkannya ke beberapa fungsi yang berjalan di awal siklus proses
jony89

1
@ jony89 setuju jika .bindtidak mengambil parameter tambahan. Tapi dalam kasus pertama memang begitu. Saya tidak berpikir ada cara lain
Dhiraj

1
Ada, buat tiga fungsi berbeda (yang dibuat oleh hasil getComponent.bind (this, 1)), meskipun pasti itu bisa menjadi keputusan (akan melakukannya untuk 2-3 komponen, bukan untuk 20 - kecuali itu benar-benar masalah kinerja dan mudah dibuat secara dinamis).
jony89

38

Berikut adalah bagaimana Anda mendefinisikan penanganan kejadian onClick react , yang menjawab judul pertanyaan ... menggunakan sintaks 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
Baik bindfungsi panah maupun panah tidak boleh digunakan di dalam rendermetode karena menghasilkan fungsi baru yang dibuat setiap saat. Ini memiliki efek mengubah status komponen, dan komponen dengan status yang diubah selalu dirender ulang. Bagi satu orang, aini bukan masalah besar. Untuk daftar yang dibuat dengan item yang dapat diklik, ini menjadi masalah besar dengan sangat cepat. Inilah mengapa secara khusus diperingatkan.
hippietrail

18

Gunakan ECMA2015. Fungsi panah membuat "ini" jauh lebih intuitif.

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
indextidak melakukan apapun disini?
utara

@northamerican - Tidak, itu hanya ada di sana untuk menambahkan beberapa kejelasan parameter
itcropper

5
Ini sebenarnya buruk untuk kinerja karena membuat fungsi baru pada setiap render. Lihat: stackoverflow.com/questions/36677733/…
Jochie Nabuurs

1
Dan tolong jangan gunakan jQuery di dalam React jika Anda tidak perlu melakukannya!
Emile Bergeron

13

Jika Anda menggunakan ES6, berikut beberapa contoh kode sederhana:

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;

Dalam badan kelas ES6, fungsi tidak lagi memerlukan kata kunci 'function' dan tidak perlu dipisahkan dengan koma. Anda juga dapat menggunakan sintaks => juga jika Anda mau.

Berikut adalah contoh dengan elemen yang dibuat secara dinamis:

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;

Perhatikan bahwa setiap elemen yang dibuat secara dinamis harus memiliki 'kunci' referensi unik.

Selain itu, jika Anda ingin meneruskan objek data aktual (bukan peristiwa) ke dalam fungsi onClick, Anda harus meneruskannya ke bind Anda. Sebagai contoh:

Fungsi onClick baru:

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

Meneruskan objek data:

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

Saya mencoba untuk membangun item li saya dinamis dan kemudian ini terlihat menjadi tidak terdefinisi dan oleh karena itu fungsi onClick melontarkan kesalahan.
mendarat

1
Saya baru saja menemukan jawaban serupa di mana Anda perlu menggunakan .bind (this)); di akhir fungsi anonim karena ini di sini merujuk ke jendela sampai Anda membuat ikatan ...
mendarat


6

Menangani kejadian dengan elemen React sangat mirip dengan menangani kejadian pada elemen DOM. Ada beberapa perbedaan sintaksis:

  • Peristiwa React diberi nama menggunakan camelCase, bukan huruf kecil.
  • Dengan JSX Anda meneruskan fungsi sebagai pengendali kejadian, bukan sebagai string.

Jadi seperti yang disebutkan dalam dokumentasi React , mereka sangat mirip dengan HTML normal dalam hal Penanganan Event, tetapi nama event di React menggunakan camelcase, karena mereka bukan benar-benar HTML, mereka adalah JavaScript, juga, Anda meneruskan fungsinya saat kami meneruskan pemanggilan fungsi dalam format string untuk HTML, keduanya berbeda, tetapi konsepnya sangat mirip ...

Lihat contoh di bawah ini, perhatikan cara event diteruskan ke fungsi:

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;


Ini tampaknya pada dasarnya identik dengan jawaban 11 poin, dan membangkitkan pertanyaan-indah atau mengapa?
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 Semoga demo ini bisa membantu :) Saya sarankan untuk mengubah warna latar belakang dengan mengganti nama kelas.


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;


dapatkah Anda memberikan lebih banyak konteks untuk kode ini dengan menjelaskan bagaimana hal ini dapat memperbaiki masalah?
MEDZ

1

Anda dapat menggunakan metode React.createClone. Buat elemen Anda, lalu buat tiruannya. Selama pembuatan klon, Anda dapat menyuntikkan alat peraga. Masukkan onClick: method prop seperti ini

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

metode changeColor akan mengatur status dengan duplikat, memungkinkan Anda untuk tetap mengatur warna dalam prosesnya.

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


Kloning sama sekali tidak diperlukan.
Emile Bergeron

-17

Ini adalah pola React non-standar (tapi tidak jarang) yang tidak menggunakan JSX, alih-alih menempatkan semuanya sebaris. Juga, itu Coffeescript.

'Cara bereaksi' untuk melakukan ini adalah dengan status komponen itu sendiri:

( 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

Contoh ini berhasil - Saya mengujinya secara lokal. Anda dapat melihat kode contoh ini tepat di github saya . Awalnya env hanya lokal untuk keperluan litbang papan tulis saya sendiri tetapi saya mempostingnya ke Github untuk ini. Ini mungkin akan dihapuskan di beberapa titik tetapi Anda dapat memeriksa komit dari 8 Sept 2016 untuk melihat ini.

Secara lebih umum, jika Anda ingin melihat bagaimana pola CS / no-JSX untuk React ini bekerja, lihat beberapa pekerjaan terbaru di sini . Mungkin saja saya akan memiliki waktu untuk menerapkan POC sepenuhnya untuk ide aplikasi ini, tumpukan yang mencakup NodeJS, Primus, Redis, & React.


latar belakang tidak perlu dolambda: Ungkapan ini juga berlaku:background: if @state.lighted_item is uid then 'magenta' else 'chartreuse'
Wylie Kulik

halo bagaimana saya bisa melihat onclick di konsol browser?
Muneem Habib

12
Mengapa Anda menggunakan CoffeeScript sebagai jawaban atas pertanyaan yang tidak menyebutkannya dengan cara apa pun? Ini tidak masuk akal dan mungkin dapat membuat jawaban lebih sulit untuk dibaca bagi penanya, karena dia mungkin tidak tahu / menyukai CoffeeScript. Merendahkan, jelas.
macbem

7
Tidak tetapi itu adalah sesuatu yang dibangun di atas bahasa, tidak mutlak tidak standar dan membutuhkan instalasi, dan kompilasi. benar-benar pilihan yang buruk untuk menulis jawaban Anda di coffeescript ketika ada NOL yang mengisyaratkan sama sekali bahwa mereka menggunakan coffeescript dalam proyek mereka
TheRealMrCrowley

4
Coffeescript hanyalah lapisan di atas js. FTFY.
machineghost
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.