La fonction React onClick se déclenche au rendu

212

Je passe 2 valeurs à un composant enfant:

  1. Liste des objets à afficher
  2. supprimer la fonction.

J'utilise une fonction .map () pour afficher ma liste d'objets (comme dans l'exemple donné dans la page du didacticiel react), mais le bouton de ce composant déclenche la onClickfonction, lors du rendu (il ne doit pas se déclencher au moment du rendu). Mon code ressemble à ceci:

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

Ma question est: pourquoi la onClickfonction se déclenche-t-elle sur le rendu et comment la désactiver?

Stralos
la source

Réponses:

528

Parce que vous appelez cette fonction au lieu de passer la fonction à onClick, changez cette ligne en ceci:

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

=> appelé Arrow Function, qui a été introduit dans ES6, et sera pris en charge sur React 0.13.3 ou supérieur.

Long Nguyen
la source
1
comment faire cela en coffescript?
vipin8169
14
Vous pouvez également éviter ces accolades de fonction flèche. Ce que je crois correspondre aux meilleures pratiques:onClick={() => this.props.removeTaskFn(todo)}
sospedra
1
Pourriez-vous expliquer cela un peu plus? J'obtiens que les gens continuent à dire que ce n'est pas la meilleure pratique mais j'aimerais comprendre ce qui se passe ici exactement avec () => Je comprends ce qu'est une fonction de flèche mais pas ce que c'est () et pourquoi c'est mauvais?
wuno
@wuno Le () est les paramètres de votre fonction anonyme. Il est vide ici car nous ne transmettons aucun paramètre. Imaginez que le () est le () de la fonction (). En ce qui concerne les raisons pour lesquelles il n'est pas recommandé de lier dans la fonction render (), c'est parce que sur chaque rendu, nous relions la fonction au composant, ce qui peut être très coûteux.
jaysonder
@LongNguyen C'est ce que je recherche! merci beaucoup
M. Wiśnicki
31

Au lieu d'appeler la fonction, liez la valeur à la fonction:

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

Réf MDN: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

Pete TNT
la source
2
À mon humble avis et bien d'autres. Vous devriez privilégier les fonctions apatrides plutôt que la fermeture ou la liaison, car celles-ci peuvent vous conduire à des effets secondaires indésirables. Par conséquent, même si les deux réponses sont correctes, je pense que l'une est plus appropriée que l'autre.
sospedra
1
La liaison directe dans le rendu ou ailleurs dans le composant n'est pas recommandée. La liaison devrait toujours se produire dans le constructeur
Hemadri Dasari
15

La valeur de votre onClickattribut doit être une fonction, pas un appel de fonction.

<button type="submit" onClick={function(){removeTaskFunction(todo)}}>Submit</button>
Brian Swisher
la source
8
N'utilisez pas de fonctions anonymes sur les appels d'événements à l'intérieur du rendu - cela déclenchera un autre rendu
Splynx
4

Pour ceux qui n'utilisent pas les fonctions fléchées mais quelque chose de plus simple ... Je l'ai rencontré lors de l'ajout de parenthèses après ma fonction signOut ...

remplacer ceci <a onClick={props.signOut()}>Log Out</a>

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

olisteadman
la source
En fait, cela ne fonctionne pas du tout pour moi. J'ai transmis la fonction et je n'ai jamais ajouté de parenthèses et elle a toujours tiré sur le rendu. Je ne sais pas si cela a changé depuis février 19, mais l'attribution d'une fonction comme dans la réponse de Long Nguyen et Vishal Bisht a résolu le problème.
BitShift
4

JSX est utilisé avec ReactJS car il est très similaire au HTML et il donne aux programmeurs l'impression d'utiliser le HTML alors qu'il transpile finalement dans un fichier javascript.

L'écriture d'une boucle for et la spécification d'une fonction en tant que {this.props.removeTaskFunction (todo)} exécuteront les fonctions chaque fois que la boucle est déclenchée.

Pour arrêter ce comportement, nous devons retourner la fonction à onClick.

La fonction flèche flèche a une instruction de retour cachée avec la propriété bind . Ainsi, il renvoie la fonction à OnClick car Javascript peut également renvoyer des fonctions !!!!!

Utilisation -

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

ce qui signifie-

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

JSX évaluera les expressions JavaScript entre accolades

Dans ce cas, this.props.removeTaskFunction(todo)est invoqué et la valeur de retour est affectée àonClick

Ce que vous devez prévoir, onClickc'est une fonction. Pour ce faire, vous pouvez encapsuler la valeur dans une fonction anonyme.

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
la source
1

J'ai eu un problème similaire, mon code était:

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

    }

Où cela devrait être

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

dans RenderRadioInput

Cela a résolu le problème pour moi.

Seyhak Ly
la source