React JS onClick gestore di eventi


120

io ho

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

Voglio colorare lo sfondo dell'elemento dell'elenco cliccato. Come posso farlo in React?

Qualcosa di simile a

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

Risposte:


95

Perchè no:

onItemClick: function (event) {

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

},

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

E se vuoi essere più reattivo al riguardo, potresti voler impostare l'elemento selezionato come stato del suo componente React che lo contiene, quindi fare riferimento a quello stato per determinare il colore dell'oggetto all'interno 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>
    );
},

Vorresti mettere quei messaggi <li>in un ciclo e devi fare in modo che gli stili li.one li.offimpostino il tuo background-color.


La manipolazione manuale del DOM in React è un anti-pattern che porta solo a più problemi. Evita cose come a event.currentTarget.style.backgroundColor = '#ccc';meno che tu non capisca veramente cosa stai facendo (il più delle volte, integrando widget di terze parti).
Emile Bergeron

61

Due modi in cui posso pensare sono

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

Questo è il mio preferito personale.

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

Ecco una DEMO

Spero che aiuti.


8
Non è consigliabile applicare il bind all'interno della funzione di rendering poiché lo farà ogni volta che il componente viene renderizzato. puoi spostarlo in una funzione che viene eseguita all'inizio del ciclo di vita
jony89

1
@ jony89 ha concordato se .bindnon accetta un parametro aggiuntivo. Ma nel primo caso lo fa. Non credo che ci sia un altro modo
Dhiraj

1
C'è, crea tre diverse funzioni (che sono state create dal risultato di getComponent.bind (questo, 1)), sebbene quella definita possa essere una decisione (lo farei per 2-3 componenti, non per 20 - a meno che non sia davvero un problema di prestazioni e facile crearlo dinamicamente).
jony89

38

Ecco come definire un gestore di eventi react onClick , che rispondeva al titolo della domanda ... usando la sintassi 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
Né le bindfunzioni freccia devono essere utilizzate all'interno dei rendermetodi perché risultano nella creazione di una nuova funzione ogni volta. Ciò ha l'effetto di modificare lo stato del componente e i componenti con stato modificato vengono sempre sottoposti a rendering. Per un single aquesto non è un grosso problema. Per elenchi generati con elementi cliccabili questo diventa un grosso problema molto rapidamente. Questo è il motivo per cui è specificamente messo in guardia contro.
Hippietrail

18

Usa ECMA2015. Le funzioni delle frecce rendono "questo" molto più intuitivo.

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
indexnon fa niente qui?
nordamericano

@northamerican - No, è solo lì per aggiungere un po 'di chiarezza sui parametri
itcropper

5
Questo in realtà è negativo per le prestazioni in quanto crea una nuova funzione a ogni rendering. Vedi: stackoverflow.com/questions/36677733/...
jochie Nabuurs

1
E per favore non usare jQuery all'interno di React se non è necessario!
Emile Bergeron

13

Se stai usando ES6, ecco un semplice codice di esempio:

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;

Nei corpi delle classi ES6, le funzioni non richiedono più la parola chiave "function" e non devono essere separate da virgole. Puoi anche usare la sintassi => se lo desideri.

Ecco un esempio con elementi creati dinamicamente:

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;

Nota che ogni elemento creato dinamicamente dovrebbe avere una "chiave" di riferimento univoca.

Inoltre, se desideri passare l'oggetto dati effettivo (piuttosto che l'evento) nella tua funzione onClick, dovrai passarlo al tuo bind. Per esempio:

Nuova funzione onClick:

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

Passaggio nell'oggetto dati:

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

Sto cercando di costruire i miei elementi li dinamici e quindi questo sembra diventare indefinito e la funzione onClick genera quindi un errore.
atterrato il

1
Ho appena trovato una risposta simile in cui devi usare .bind (this)); alla fine della funzione anonima poiché qui si riferisce alla finestra fino a quando non si effettua il binding ...
atterrato il


6

La gestione degli eventi con gli elementi React è molto simile alla gestione degli eventi sugli elementi DOM. Ci sono alcune differenze sintattiche:

  • Gli eventi React sono denominati utilizzando camelCase, piuttosto che minuscolo.
  • Con JSX si passa una funzione come gestore di eventi, piuttosto che una stringa.

Quindi, come menzionato nella documentazione di React , sono abbastanza simili al normale HTML quando si tratta di gestione degli eventi, ma i nomi degli eventi in React usano camelcase, perché non sono realmente HTML, sono JavaScript, inoltre, passi la funzione mentre passiamo la chiamata di funzione in un formato stringa per HTML, sono diversi, ma i concetti sono abbastanza simili ...

Guarda l'esempio qui sotto, presta attenzione al modo in cui l'evento viene passato alla funzione:

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;


Questo sembra essenzialmente identico alla risposta in 11 punti e fa risorgere una bella o domanda perché?
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 Spero che questa demo possa aiutare :) Consiglio di cambiare il colore di sfondo attivando il nome della classe.


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;


puoi fornire più contesto a questo codice spiegando come questo potrebbe risolvere il problema?
MEDZ

1

Puoi utilizzare il metodo React.createClone. Crea il tuo elemento, piuttosto che crearne un clone. Durante la creazione del clone, puoi iniettare oggetti di scena. Iniettare un puntello onClick: method come questo

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

il metodo changeColor imposterà lo stato con il duplicato, consentendo di impostare il colore nel processo.

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


La clonazione è totalmente inutile.
Emile Bergeron il

-17

Questo è un pattern React non standard (ma non così raro) che non usa JSX, ma mette tutto in linea. Inoltre, è Coffeescript.

Il "modo di reagire" per farlo sarebbe con lo stato del componente:

( 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

Questo esempio funziona: l'ho testato localmente. Puoi controllare questo codice di esempio esattamente sul mio GitHub . Originariamente l'env era solo locale per i miei scopi di ricerca e sviluppo sulla lavagna, ma l'ho pubblicato su Github per questo. Ad un certo punto potrebbe essere scritto, ma puoi controllare il commit dell'8 settembre 2016 per vederlo.

Più in generale, se vuoi vedere come funziona questo pattern CS / no-JSX per React, dai un'occhiata ad alcuni lavori recenti qui . È possibile che avrò tempo per implementare completamente un POC per questa idea di app, lo stack per il quale include NodeJS, Primus, Redis e React.


lo sfondo non deve essere necessariamente un dolambda: Questa espressione funziona anche:background: if @state.lighted_item is uid then 'magenta' else 'chartreuse'
Wylie Kulik

ciao come posso visualizzare onclick sulla console del browser?
Muneem Habib

12
Perché dovresti usare CoffeeScript in una risposta a una domanda che non lo menziona in alcun modo? Non ha alcun senso e probabilmente può rendere la risposta più difficile da leggere per il richiedente, poiché potrebbe non conoscere / apprezzare CoffeeScript. Downvoting, ovviamente.
macbem

7
No, ma è qualcosa che si basa sulla lingua, non è assolutamente standard e richiede installazione e compilazione. è stata davvero una cattiva scelta scrivere la tua risposta in coffeescript quando ZERO suggerisce che stanno usando coffeescript nel loro progetto
TheRealMrCrowley

4
Coffeescript è solo uno strato sopra js. FTFY.
machineghost
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.