当我需要传递参数时,JSX props中没有 .bind() 或箭头函数对我来说毫无意义

IT技术 javascript reactjs eslint
2021-04-27 05:22:54

查看 eslint 规则,在 JSX Props 中没有 .bind() 或箭头函数

它说不要使用、箭头函数或绑定:

<div onClick={this._handleClick.bind(this)}></div>
<div onClick={() => console.log('Hello!'))}></div>

而是使用:

<div onClick={this._handleClick}></div>

这一切都很好,但我如何在点击事件上将参数传递给这个函数?

这是我的天真代码示例:

export class UserList extends Component {
  constructor(props) {
    super(props);
    this.handleToggleActive = this.handleToggleActive.bind(this);
  }
  handleToggleActive() {
    console.log(arguments);
  }
  render() {
    return (
      <ul className="user-list">
        {this
          .props
          .users
          .map(user => (
            <li key={user.id}>
              <Link to={`/users/${user.id}`}>{user.name}</Link>
              <Button onClick={this.handleToggleActive}>Toggle Active</Button>
            </li>
          ))}
      </ul>
    );
  }
}

我如何获得user.id我的handleToggleActive功能?当我尝试类似的事情时:

<Button onClick={this.handleToggleActive(user.id)}>Toggle Active</Button>

它在渲染时执行,我能看到的唯一其他方法是使用箭头函数?

这样做的正确方法是什么?

4个回答

使用绑定和箭头函数,将创建一个新函数,将一个全新的 prop 传递给您的组件,导致不必要的重新渲染和垃圾收集器的额外工作,使用数据属性是一个糟糕的设计,而不是 React 的做事方式,你不应该直接访问 DOM,而是让 React 处理事情。相反,您可以创建一个新组件并将处理程序作为props传递,在组件的方法中处理 id 的“绑定”:

class User extends Component {
  handleClick() {
    this.props.handleToggleActive(this.props.user.id);
  }

  render() {
    return (
       <li>
         <Link to={`/users/${this.props.user.id}`}>{this.props.user.name}</Link>
         <Button onClick={this.handleClick}>Toggle Active</Button>
      </li>
    )
  } 
}

export class UserList extends Component {
  constructor(props) {
    super(props);
    this.handleToggleActive = this.handleToggleActive.bind(this);
  }
  handleToggleActive(userId) {
    console.log(userId);
  }
  render() {
    return (
      <ul className="user-list">
        {this
          .props
          .users
          .map(user => (
            <User key={user.id} user={user} handleToggleActive={this.handleToggleActive} />
          ))}
      </ul>
    );
  }
}

我想你可以使用data-*属性。

export class UserList extends Component {
    constructor(props) {
        super(props);
        this.handleToggleActive = this.handleToggleActive.bind(this);
    }
    handleToggleActive(event) {
        console.log(event.target.dataset.id);
    }
    render() {
        return (
            <ul className="user-list">
                {this
                .props
                .users
                .map(user => (
                    <li key={user.id}>
                    <Link to={`/users/${user.id}`}>{user.name}</Link>
                    <Button onClick={this.handleToggleActive} data-id={user.id}>Toggle Active</Button>
                    </li>
                ))}
            </ul>
        );
    }
}

为了解决性能问题(这就是规则存在的原因),使用 memoization 怎么样?

例如,lru-memoize你得到的包(带有一个哑组件)类似于:

var memoize100 = require('lru-memoize')(100);

let handleToggleActive = (user) => () => {
    console.log(user.id)
}
handleToggleActive = memoize100(handleToggleActive)

const UserList = (props) =>
  <ul className="user-list">
  { props.users
      .map(user => (
        <li key={user.id}>
          <Link to={`/users/${user.id}`}>{user.name}</Link>
          <Button onClick={handleToggleActive(user)}>Toggle Active</Button>
        </li>
      ))
    }
  </ul>

每次渲染组件时,使用箭头函数或绑定将创建一个不同的回调实例。因此,每次都会重新创建该函数,并且旧的函数被垃圾收集,从而导致垃圾收集器过载。此外,由于这个原因,纯组件和在 shouldcomponentupdate 中具有浅比较的组件将始终重新渲染,因为它会发现其 props 的变化,因为旧函数被丢弃,并且每次渲染父组件时都会创建一个新函数。

我们可以使用带有柯里化的属性初始化器语法来避免在 JSX 代码中使用绑定或箭头函数。

handleClick = (param) => (e) => {
  console.log('Event', e);
  console.log('Parameter', param);
}

render() {
  <button onClick={this.handleClick('Parameter')}></button>
}