Реакция функции onClick срабатывает при рендере

212

Я передаю 2 значения дочернему компоненту:

  1. Список объектов для отображения
  2. удалить функцию.

Я использую функцию .map () для отображения моего списка объектов (как в примере, приведенном на странице руководства по реагированию), но кнопка в этом компоненте вызывает onClickфункцию при рендеринге (она не должна срабатывать во время рендеринга). Мой код выглядит так:

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

Мой вопрос: почему onClickфункция рендеринга срабатывает и как сделать так, чтобы она не выполнялась?

Stralos
источник

Ответы:

528

Поскольку вы вызываете эту функцию вместо передачи функции в onClick, измените эту строку на следующую:

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

=> называется Arrow Function, которая была представлена ​​в ES6 и будет поддерживаться в React 0.13.3 или более поздней версии.

Лонг Нгуен
источник
1
как это сделать в coffescript?
vipin8169
14
Вы можете избежать этих фигурных скобок со стрелками. Как я полагаю, соответствуют лучшим практикам:onClick={() => this.props.removeTaskFn(todo)}
Соспедра
1
Не могли бы вы объяснить это немного больше? Я понимаю, что люди продолжают говорить, что это не лучшая практика, но я хотел бы понять, что именно здесь происходит, с помощью () => Я понимаю, что такое функция со стрелкой, а не что это такое () и почему это плохо?
Вуно
@wuno () - это параметры вашей анонимной функции. Здесь пусто, потому что мы не передаем никаких параметров. Представьте, что () - это () функции (). Теперь о том, почему это не лучший метод для связывания в функции render (), потому что при каждом рендеринге мы привязываем функцию к компоненту, что может быть очень дорогостоящим.
Jaysonder
@LongNguyen Это то, что я ищу!
Большое
31

Вместо вызова функции свяжите значение с функцией:

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

Ссылка на MDN: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

Пит ТНТ
источник
2
ИМХО и многие другие. Вы должны отдавать предпочтение функциям без сохранения состояния, а не обязательным или обязательным, потому что они могут привести к нежелательным побочным эффектам. Поэтому, даже при том, что оба ответа верны, я считаю, что один является более подходящим, чем другой.
Соспедра
1
Прямое связывание в рендере или в другом месте компонента не рекомендуется. Привязка должна всегда происходить в конструкторе
Хемадри Дасари
15

Значением вашего onClickатрибута должна быть функция, а не вызов функции.

<button type="submit" onClick={function(){removeTaskFunction(todo)}}>Submit</button>
Брайан Суишер
источник
8
Не используйте анонимные функции при вызовах событий внутри рендера - это вызовет другой рендеринг
Splynx
4

Для тех, кто не использует функции стрелок, но что-то попроще ... Я сталкивался с этим при добавлении скобок после моей функции signOut ...

замени это <a onClick={props.signOut()}>Log Out</a>

с этим <a onClick={props.signOut}>Log Out</a>...! 😆

olisteadman
источник
На самом деле это не работает для меня вообще. Я передал функцию и никогда не добавлял круглые скобки, и она все еще запускалась при рендере. Не уверен, что это изменилось с февраля 1919 года, но назначение функции, как в ответе Лонг Нгуена и Вишала Бишта, решило проблему.
BitShift
4

JSX используется с ReactJS, так как он очень похож на HTML и дает программистам ощущение использования HTML, тогда как в конечном итоге он переносится в файл javascript.

Написание цикла for и указание функции как {this.props.removeTaskFunction (todo)} будет выполнять функции всякий раз, когда цикл запускается.

Чтобы остановить это, нам нужно вернуть функцию в onClick.

Функция толстой стрелки имеет скрытое выражение return вместе со свойством bind . Таким образом, он возвращает функцию в OnClick, так как Javascript тоже может возвращать функции !!!!!

Используйте -

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

что значит-

var onClick = function() {
  return this.props.removeTaskFunction(todo);
}.bind(this);
Вишал Бишт
источник
1

JSX будет оценивать выражения JavaScript в фигурных скобках

В этом случае this.props.removeTaskFunction(todo)вызывается и возвращаемое значение присваиваетсяonClick

То, что вы должны обеспечить, onClickявляется функцией. Для этого вы можете обернуть значение в анонимную функцию.

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>
        );
    }
});
Судо Бэнгбэнг
источник
1

У меня была похожая проблема, мой код был:

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

    }

Где это должно быть

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

в RenderRadioInput

Это исправило проблему для меня.

Сейхак Ли
источник