Reagieren onClick-Funktion wird beim Rendern ausgelöst

209

Ich übergebe 2 Werte an eine untergeordnete Komponente:

  1. Liste der anzuzeigenden Objekte
  2. Löschfunktion.

Ich verwende eine .map () -Funktion, um meine Liste von Objekten anzuzeigen (wie in dem Beispiel auf der Seite mit dem Reaktions-Tutorial), aber die Schaltfläche in dieser Komponente löst die onClickFunktion beim Rendern aus (sie sollte beim Rendern nicht ausgelöst werden). Mein Code sieht folgendermaßen aus:

module.exports = React.createClass({
    render: function(){
        var taskNodes = this.props.todoTasks.map(function(todo){
            return (
                <div>
                    {todo.task}
                    <button type="submit" onClick={this.props.removeTaskFunction(todo)}>Submit</button>
                </div>
            );
        }, this);
        return (
            <div className="todo-task-list">
                {taskNodes}
            </div>
        );
    }
});

Meine Frage ist: Warum wird die onClickFunktion beim Rendern ausgelöst und wie kann sie nicht ausgelöst werden?

Stralos
quelle

Antworten:

526

Da Sie diese Funktion aufrufen, anstatt sie an onClick zu übergeben, ändern Sie diese Zeile in folgende Zeile:

<button type="submit" onClick={() => { this.props.removeTaskFunction(todo) }}>Submit</button>

=> genannt Arrow Function, die in ES6 eingeführt wurde und in React 0.13.3 oder höher unterstützt wird.

Langer Nguyen
quelle
1
wie geht das in coffescript?
Vipin8169
14
Sie können diese geschweiften Klammern auch vermeiden. Was ich für die besten Praktiken onClick={() => this.props.removeTaskFn(todo)}
halte
1
Würden Sie das bitte etwas näher erläutern? Ich verstehe, dass die Leute immer wieder sagen, es sei keine bewährte Methode, aber ich würde gerne verstehen, was hier genau mit () => passiert. Ich verstehe, was eine Pfeilfunktion ist, aber nicht, was dies ist () und warum dies schlecht ist.
Wuno
@wuno Das () ist der Parameter Ihrer anonymen Funktion. Es ist hier leer, weil wir keine Parameter übergeben. Stellen Sie sich vor, dass () das () von function () ist. Die Frage, warum das Binden in der Funktion render () nicht die beste Vorgehensweise ist, liegt darin, dass wir bei jedem Rendern die Funktion erneut an die Komponente binden, was sehr kostspielig sein kann.
Jaysonder
@ LongNguyen Das ist was ich suche!
Vielen
31

Binden Sie den Wert an die Funktion, anstatt die Funktion aufzurufen:

this.props.removeTaskFunction.bind(this, todo)

MDN-Referenz: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

Pete TNT
quelle
2
IMHO und viele andere. Sie sollten staatenlose Funktionen gegenüber Clasess oder Binding bevorzugen, da diese zu unerwünschten Nebenwirkungen führen können. Selbst wenn beide Antworten richtig sind, glaube ich, dass eine passender ist als die andere.
Sospedra
1
Eine direkte Bindung beim Rendern oder an einer anderen Stelle in der Komponente wird nicht empfohlen. Die Bindung sollte immer im Konstruktor erfolgen
Hemadri Dasari
15

Der Wert für Ihr onClickAttribut sollte eine Funktion sein, kein Funktionsaufruf.

<button type="submit" onClick={function(){removeTaskFunction(todo)}}>Submit</button>
Brian Swisher
quelle
8
Verwenden Sie keine anonymen Funktionen für Ereignisaufrufe innerhalb von Render - es wird ein weiteres Rendering
ausgelöst
4

Für diejenigen, die keine Pfeilfunktionen verwenden, aber etwas Einfacheres ... Ich habe dies beim Hinzufügen von Klammern nach meiner signOut-Funktion festgestellt ...

Ersetzen Sie diese <a onClick={props.signOut()}>Log Out</a>

damit <a onClick={props.signOut}>Log Out</a>...! 😆

Olisteadman
quelle
Eigentlich funktioniert das bei mir überhaupt nicht. Ich habe die Funktion weitergegeben und nie Klammern hinzugefügt, und sie wurde beim Rendern immer noch ausgelöst. Ich bin mir nicht sicher, ob sich dies seit dem 19. Februar geändert hat, aber die Zuweisung einer Funktion wie in der Antwort von Long Nguyen und Vishal Bisht hat das Problem behoben.
BitShift
4

JSX wird mit ReactJS verwendet, da es HTML sehr ähnlich ist und Programmierern das Gefühl gibt, HTML zu verwenden, während es letztendlich in eine Javascript-Datei transpiliert wird.

Wenn Sie eine for-Schleife schreiben und die Funktion als {this.props.removeTaskFunction (todo)} angeben, werden die Funktionen ausgeführt, wenn die Schleife ausgelöst wird.

Um dieses Verhalten zu stoppen, müssen wir die Funktion an onClick zurückgeben.

Die Fettpfeilfunktion hat eine versteckte return- Anweisung zusammen mit der bind-Eigenschaft . Somit wird die Funktion an OnClick zurückgegeben, da Javascript auch Funktionen zurückgeben kann !!!!!

Verwenden -

onClick={() => { this.props.removeTaskFunction(todo) }}

was bedeutet-

var onClick = function() {
  return this.props.removeTaskFunction(todo);
}.bind(this);
Vishal Bisht
quelle
1

JSX wird auswerten JavaScript-Ausdrücke in geschweiften Klammern aus

In diesem Fall, this.props.removeTaskFunction(todo) wird aufgerufen und der Rückgabewert zugewiesenonClick

Was Sie bereitstellen müssen, onClickist eine Funktion. Dazu können Sie den Wert in eine anonyme Funktion einschließen.

export const samepleComponent = ({todoTasks, removeTaskFunction}) => {
    const taskNodes = todoTasks.map(todo => (
                <div>
                    {todo.task}
                    <button type="submit" onClick={() => removeTaskFunction(todo)}>Submit</button>
                </div>
            );
    return (
        <div className="todo-task-list">
            {taskNodes}
        </div>
        );
    }
});
Sudo Bangbang
quelle
1

Ich hatte ein ähnliches Problem, mein Code war:

function RadioInput(props) {
    return (
    <div className="form-check form-check-inline">
        <input className="form-check-input" type="radio" name="inlineRadioOptions" id={props.id} onClick={props.onClick} value={props.label}></input>
        <label className="form-check-label" htmlFor={props.id}>{props.label}</label>
    </div>
    );
  }
class ScheduleType extends React.Component
{
    renderRadioInput(id,label)
    {
        id = "inlineRadio"+id;
        return(
            <RadioInput
                id = {id}
                label = {label}
                onClick = {this.props.onClick}
            />
        );

    }

Wo es sein sollte

onClick = {() => this.props.onClick()}

in RenderRadioInput

Es hat das Problem für mich behoben.

Seyhak Ly
quelle