A função React onClick é acionada na renderização

212

Eu passo 2 valores para um componente filho:

  1. Lista de objetos a serem exibidos
  2. função de exclusão.

Eu uso uma função .map () para exibir minha lista de objetos (como no exemplo dado na página do tutorial de reação), mas o botão desse componente aciona a onClickfunção no render (ele não deve acionar no tempo de renderização). Meu código fica assim:

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

Minha pergunta é: por que a onClickfunção dispara no render e como fazê-lo não funcionar?

Stralos
fonte

Respostas:

528

Como você está chamando essa função em vez de passar a função para onClick, altere essa linha para isso:

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

=> chamada Seta Função, que foi introduzida no ES6, e será suportada no React 0.13.3 ou superior.

Long Nguyen
fonte
1
como fazer isso em coffescript?
Vipin8169
14
Você também pode evitar esses aparelhos com função de seta. Que eu acredito que coincidam com as melhores práticas:onClick={() => this.props.removeTaskFn(todo)}
sospedra 05/10
1
Você poderia explicar isso um pouco mais? Entendo que as pessoas continuam dizendo que não é uma prática recomendada, mas gostaria de entender o que está acontecendo aqui exatamente com () => Entendo o que é uma função de seta, mas não o que é isso () e por que isso é ruim?
wuno
@wuno The () são os parâmetros da sua função anônima. Está vazio aqui porque não estamos transmitindo nenhum parâmetro. Imagine que o () é o () da função (). Agora, por que não é uma boa prática para ligação na função render (), porque em cada renderização, estamos religando a função ao componente, o que pode ser muito caro.
precisa saber é
@LongNguyen É isso que eu estou procurando! muito obrigado
M. Wiśnicki 4/19/19
31

Em vez de chamar a função, vincule o valor à função:

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

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

Pete TNT
fonte
2
IMHO e muitos outros. Você deve favorecer funções sem estado ao invés de clasess ou vinculação, porque elas podem levar você a efeitos colaterais indesejados. Portanto, mesmo estando as duas respostas corretas, acredito que uma seja mais apropriada do que a outra.
Sospedra
1
A ligação direta na renderização ou em qualquer outro lugar do componente não é recomendada. Vinculativo deve acontecer sempre no construtor
Hemadri Dasari
15

O valor para o seu onClickatributo deve ser uma função, não uma chamada de função.

<button type="submit" onClick={function(){removeTaskFunction(todo)}}>Submit</button>
Brian Swisher
fonte
8
Não use funções anônimas em chamadas de eventos no interior render - ele irá acionar outro tornar
Splynx
4

Para aqueles que não usam funções de seta, mas algo mais simples ... Encontrei isso ao adicionar parênteses após minha função signOut ...

substitua isso <a onClick={props.signOut()}>Log Out</a>

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

olisteadman
fonte
Na verdade, isso não está funcionando para mim. Passei a função e nunca adicionei parênteses e ela ainda disparava na renderização. Não tenho certeza se isso mudou desde fevereiro de 19, mas atribuir uma função como na resposta de Long Nguyen e Vishal Bisht corrigiu o problema.
BitShift
4

O JSX é usado com o ReactJS, pois é muito semelhante ao HTML e dá aos programadores a sensação de usar HTML, ao passo que, em última análise, transpila para um arquivo javascript.

Escrever um loop for e especificar uma função como {this.props.removeTaskFunction (todo)} executará as funções sempre que o loop for acionado.

Para interromper esse comportamento, precisamos retornar a função para onClick.

A função de seta gorda possui uma declaração de retorno oculta junto com a propriedade bind . Assim, ele retorna a função ao OnClick, pois o Javascript também pode retornar funções !!!!!

Usar -

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

que significa-

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

O JSX avaliará expressões JavaScript em chaves

Nesse caso, this.props.removeTaskFunction(todo)é chamado e o valor de retorno é atribuído aonClick

O que você precisa prever onClické uma função. Para fazer isso, você pode agrupar o valor em uma função anônima.

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
fonte
1

Eu tive um problema semelhante, meu código era:

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

    }

Onde deveria estar

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

em RenderRadioInput

Corrigiu o problema para mim.

Seyhak Ly
fonte