Reagieren Sie auf den JS onClick-Ereignishandler

120

ich habe

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

Ich möchte den Hintergrund des angeklickten Listenelements einfärben. Wie kann ich das in React machen?

Etwas wie

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

Antworten:

95

Warum nicht:

onItemClick: function (event) {

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

},

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

Wenn Sie reaktiver sein möchten, können Sie das ausgewählte Element als Status der enthaltenen React-Komponente festlegen und dann auf diesen Status verweisen, um die Farbe des Elements zu bestimmen 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>
    );
},

Sie möchten diese <li>s in eine Schleife setzen, und Sie müssen die li.onund li.offStile so einstellen, dass sie Ihre sind background-color.

ericsoco
quelle
Die manuelle DOM-Manipulation in React ist ein Anti-Pattern, das nur zu weiteren Problemen führt. Vermeiden Sie Dinge wie, es event.currentTarget.style.backgroundColor = '#ccc';sei denn, Sie verstehen wirklich, was Sie tun (meistens, während Sie Widgets von Drittanbietern integrieren).
Emile Bergeron
61

Ich kann mir zwei Möglichkeiten vorstellen

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

Das ist mein persönlicher Favorit.

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

Hier ist eine DEMO

Ich hoffe das hilft.

Dhiraj
quelle
8
Es wird nicht empfohlen, die Bindung innerhalb der Renderfunktion anzuwenden, da dies jedes Mal erfolgt, wenn die Komponente gerendert wird. Sie können es zu einer Funktion verschieben, die zu Beginn des Lebenszyklus ausgeführt wird
jony89
1
@ jony89 stimmte zu, wenn .bindkein zusätzlicher Parameter verwendet wird. Aber im ersten Fall schon. Ich glaube nicht, dass es einen anderen Weg gibt
Dhiraj
1
Es gibt drei verschiedene Funktionen (die durch das Ergebnis von getComponent.bind (this, 1) erstellt wurden), obwohl dies definitiv eine Entscheidung sein kann (würde dies für 2-3 Komponenten tun, nicht für 20 - es sei denn, es handelt sich wirklich um ein Leistungsproblem und einfach dynamisch zu erstellen).
Jony89
38

So definieren Sie einen React onClick-Ereignishandler , der den Fragentitel mit der es6-Syntax beantwortet hat

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
quelle
9
Weder bindnoch Pfeilfunktionen sollten in renderMethoden verwendet werden , da sie dazu führen, dass jedes Mal eine neue Funktion erstellt wird. Dies hat zur Folge, dass der Status der Komponente geändert wird und Komponenten mit geändertem Status immer neu gerendert werden. Für eine Single aist das keine große Sache. Bei generierten Listen mit anklickbaren Elementen wird dies sehr schnell zu einer großen Sache. Deshalb wird ausdrücklich davor gewarnt.
Hippietrail
18

Verwenden Sie ECMA2015. Pfeilfunktionen machen "dies" viel intuitiver.

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
quelle
2
indexmacht hier nichts?
Nordamerikaner
@northamerican - Nein, es ist nur da, um einige Parameter Klarheit hinzuzufügen
itcropper
5
Dies ist tatsächlich schlecht für die Leistung, da bei jedem Rendern eine neue Funktion erstellt wird. Siehe: stackoverflow.com/questions/36677733/…
Jochie Nabuurs
1
Und bitte verwenden Sie jQuery nicht in React, wenn Sie nicht müssen!
Emile Bergeron
13

Wenn Sie ES6 verwenden, finden Sie hier einen einfachen Beispielcode:

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;

In ES6-Klassenkörpern benötigen Funktionen nicht mehr das Schlüsselwort 'function' und müssen nicht durch Kommas getrennt werden. Wenn Sie möchten, können Sie auch die Syntax => verwenden.

Hier ist ein Beispiel mit dynamisch erstellten Elementen:

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;

Beachten Sie, dass jedes dynamisch erstellte Element einen eindeutigen Referenzschlüssel haben sollte.

Wenn Sie das eigentliche Datenobjekt (und nicht das Ereignis) an Ihre onClick-Funktion übergeben möchten, müssen Sie dies an Ihre Bindung übergeben. Beispielsweise:

Neue onClick-Funktion:

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

Übergabe des Datenobjekts:

{this.state.data.map(d => {
    return(
      <li key={d.id} onClick={this.getComponent.bind(this, d)}>{d.name}</li>
    )}
)}
Dirtigr00vz
quelle
Ich versuche, meine li-Elemente dynamisch aufzubauen, und dann wird dies undefiniert, und die onClick-Funktion gibt daher einen Fehler aus.
landete
1
Ich habe gerade eine ähnliche Antwort gefunden, bei der Sie .bind (this) verwenden müssen. am Ende der anonymen Funktion, da dies hier auf Fenster verweist, bis Sie die Bindung machen ...
landete
6

Die Behandlung von Ereignissen mit React-Elementen ist der Behandlung von Ereignissen mit DOM-Elementen sehr ähnlich. Es gibt einige syntaktische Unterschiede:

  • Reaktionsereignisse werden nicht mit Kleinbuchstaben, sondern mit camelCase benannt.
  • Mit JSX übergeben Sie eine Funktion als Ereignishandler und nicht als Zeichenfolge.

Wie in der React- Dokumentation erwähnt, sind sie in Bezug auf die Ereignisbehandlung dem normalen HTML-Code ziemlich ähnlich, aber die Ereignisnamen in React verwenden camelcase, da sie nicht wirklich HTML sind, sondern JavaScript. Außerdem übergeben Sie die Funktion, während wir den Funktionsaufruf übergeben In einem String-Format für HTML sind sie unterschiedlich, aber die Konzepte sind ziemlich ähnlich ...

Schauen Sie sich das folgende Beispiel an und achten Sie darauf, wie das Ereignis an die Funktion übergeben wird:

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

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}
Alireza
quelle
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;

Jalaleddin Hosseini
quelle
Dies scheint im Wesentlichen identisch mit der 11-Punkte-Antwort zu sein und lässt ein hübsches oder fragendes Warum wieder auferstehen.
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 Hoffe, diese Demo kann helfen :) Ich empfehle, die Hintergrundfarbe durch Umschalten des Klassennamens zu ändern.

dabeng
quelle
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
quelle
Können Sie diesem Code mehr Kontext geben, indem Sie erläutern, wie das Problem dadurch behoben werden kann?
MEDZ
1

Sie können die React.createClone-Methode verwenden. Erstellen Sie Ihr Element, und erstellen Sie dann einen Klon davon. Während der Erstellung des Klons können Sie Requisiten injizieren. Injizieren Sie eine solche onClick: -Methoden-Requisite

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

Die changeColor-Methode legt den Status mit dem Duplikat fest, sodass Sie die Farbe während des Vorgangs festlegen können.

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

Eddie D.
quelle
Das Klonen ist völlig unnötig.
Emile Bergeron
-17

Dies ist ein nicht standardmäßiges (aber nicht so ungewöhnliches) Reaktionsmuster, das kein JSX verwendet, sondern alles inline setzt. Es ist auch Coffeescript.

Der "Reaktionsweg", um dies zu tun, wäre mit dem eigenen Zustand der Komponente:

( 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

Dieses Beispiel funktioniert - ich habe es lokal getestet. Sie können diesen Beispielcode genau bei meinem Github auschecken . Ursprünglich war das env nur für meine eigenen Whiteboard-Forschungs- und Entwicklungszwecke lokal, aber ich habe es dafür auf Github gepostet. Es wird möglicherweise irgendwann überschrieben, aber Sie können das Commit vom 8. September 2016 überprüfen, um dies zu sehen.

Allgemeiner gesagt , wenn Sie , wie diese CS / no-JSX Muster für React Werke sehen wollen Besuche einige neuere Arbeiten hier . Möglicherweise habe ich Zeit, einen POC für diese App-Idee vollständig zu implementieren. Der Stack enthält NodeJS, Primus, Redis und React.

Wylie Kulik
quelle
Der Hintergrund muss kein doLambda sein: Dieser Ausdruck funktioniert auch:background: if @state.lighted_item is uid then 'magenta' else 'chartreuse'
Wylie Kulik
Hallo, wie kann ich onclick auf der Browserkonsole anzeigen?
Muneem Habib
12
Warum sollten Sie CoffeeScript für die Beantwortung einer Frage verwenden, in der es in keiner Weise erwähnt wird? Es macht keinen Sinn und kann es wahrscheinlich schwieriger machen, die Antwort für den Fragesteller zu lesen, da er CoffeeScript möglicherweise nicht kennt / mag. Offensichtlich Downvoting.
Macbem
7
Nein, aber es basiert auf der Sprache, ist absolut nicht Standard und erfordert die Installation und Kompilierung. Es war wirklich eine schlechte Wahl, Ihre Antwort in Coffeescript zu schreiben, wenn es NULL Hinweise darauf gibt, dass sie Coffeescript in ihrem Projekt verwenden
TheRealMrCrowley
4
Coffeescript ist nur eine Schicht über js. FTFY.
Machineghost