Вы правы, есть множество способов обрабатывать обработчики (ba-dum-tss). React существует уже некоторое время, и лицо JavaScript за это время совсем немного изменилось.
В документации React есть целая страница, посвященная обработке событий , но тем не менее вот сравнение некоторых способов обработки обратных вызовов:
class MyComponent extends React.Component {
constructor (props) {
super(props)
this.boundHandleClick = this.boundHandleClick.bind(this)
}
arrowHandleClick = (event) => { this.props.onClick(event.target.id) }
boundHandleClick (event) { this.props.onClick(event.target.id) }
boundInRenderHandleClick (event) { this.props.onClick(event.target.id) }
unboundHandleClick (event) { this.props.onClick(event.target.id) }
render () {
return (
<div>
<button id='zero' onClick={(event) => { this.props.onClick(event.target.id) }} />
<button id='one' onClick={arrowHandleClick} />
<button id='two' onClick={boundHandleClick} />
<button id='three' onClick={boundInRenderHandleClick.bind(this)} />
<button id='four' onClick={unboundHandleClick} />
</div>
)
}
}
При нажатии:
#zero
будет правильно вызывать props.onClick
. Проблема в том, что анонимная функция, созданная в методе рендеринга, будет воссоздавать при каждом рендеринге. Это плохо для производительности.
#one
будет правильно вызывать props.onClick
. Поскольку обратный вызов определяется как метод класса, он будет создан только тогда, когда MyComponent
создается (и монтируется). Это приемлемый способ определения обратного вызова. Видимо медленнее, чем когда-то думали , но, на мой взгляд, он самый аккуратный.
#two
правильно вызовет props.onClick
. По сути, это то же самое, что arrowHandleClick
, только это связанная функция в отличие от стрелочной функции. Для всех намерений и целей они одинаковы - , но обязательно копайтесь в различиях .
#three
будет правильно вызывать props.onClick
, и он имеет тот же результат, что и #two
, но оказывает негативное влияние на производительность, как #zero
- функции не должны создаваться или связываться в методе рендеринга.
#four
не будет работать правильно и выдаст ошибку. При запуске this
будет ссылаться на элемент (в данном случае #four
), а не на экземпляр класса. Во всех других обработчиках this
относится к экземпляру класса React, который имеет props.onClick
.
Теперь есть новый общепринятый способ написания компонентов: использование простых функций и хуков. . this
ушел в прошлое.
const MyComponent = (props) => {
const handleClick = event => props.handleClick(event.target.id)
const memoizedHandleClick = React.useCallback(
event => props.handleClick(event.target.id),
[props.handleClick]
)
return (
<div>
<button id='zero' onClick={event => props.handleClick(event.target.id)} />
<button id='one' onClick={handleClick} />
<button id='two' onClick={memoizedHandleClick} />
</div>
)
}
Здесь все обратные вызовы работают правильно - с той лишь разницей, что memoizedHandleClick
не будет воссоздаваться при каждом рендеринге, если props.handleClick
не изменится. По моему собственному опыту, оба варианта приемлемы, и люди, похоже, больше не возражают против воссоздания обратных вызовов в функциональных компонентах, а скорее проявляют прагматичность c и решают проблемы с производительностью, когда вы с ними сталкиваетесь.