首页 > 解决方案 > 如何决定在 React 中调用处理函数的最有效方式?

问题描述

我对 React 还是很陌生,但我意识到定义回调函数有两种常见的方法:

// Method 1
private handleInputChange = (event) => {
    this.setState({name: event.target.value});
}
// Method 2
private handleInputChange(event){
    this.setState({name:event.target.value});
}

在 DOM 元素内部(对于这个例子,让我们使用<input>),可以通过不同的方法调用处理程序,例如:

// Method 1
<input
    type="text"
    onChange={this.handleInputChange}
/>

// Method 2
<input
    type="text"
    onChange={(e) => this.handleInputChange(e)}
/>

// Method 3 (assume the function don't have parameters)
<input
    type="text"
    onChange={this.handleNewThing()}
/>

我的问题是,使用哪种方法合适?我真的对所有这些方法感到困惑。然后我看到人们bind()出于某种原因包括在内?

标签: javascriptreactjstypescript

解决方案


你是对的,有很多方法可以处理处理程序(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不应在 render 方法中创建或绑定函数。

  • #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发生变化。根据我自己的经验,两者都是可以接受的,人们似乎不再介意在功能组件中重新创建回调 - 而是在遇到它们时务实并解决性能问题。


推荐阅读