事件处理

对于事件处理,React 提供了一系列属性。解决方案几乎和使用标准化 DOM 完全一样。也有一些不同点,比如使用驼峰式或传入的是函数,但总体来说,还是十分相似的。

  1. const theLogoIsClicked = () => alert('Clicked');
  2. <Logo onClick={ theLogoIsClicked } />
  3. <input
  4. type='text'
  5. onChange={event => theInputIsChanged(event.target.value) } />

通常,我们在包含派发事件的元素的组件中处理事件。比如在下面的示例中,我们有一个事件处理函数,我们想要在同一个组件中运行函数或方法:

  1. class Switcher extends React.Component {
  2. render() {
  3. return (
  4. <button onClick={ this._handleButtonClick }>
  5. click me
  6. </button>
  7. );
  8. }
  9. _handleButtonClick() {
  10. console.log('Button is clicked');
  11. }
  12. };

这样使用完全可以,因为 _handleButtonClick 是一个函数,而我们也确实将这个函数传给了 onClick 属性。问题是这段代码中并没有保持同一个上下文。所以,如果我们在 _handleButtonClick 函数中使用 this 来获取 Switcher 组件的引用时将会报错。

  1. class Switcher extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = { name: 'React in patterns' };
  5. }
  6. render() {
  7. return (
  8. <button onClick={ this._handleButtonClick }>
  9. click me
  10. </button>
  11. );
  12. }
  13. _handleButtonClick() {
  14. console.log(`Button is clicked inside ${ this.state.name }`);
  15. // 导致
  16. // Uncaught TypeError: Cannot read property 'state' of null
  17. }
  18. };

通常,我们使用 bind 来解决:

  1. <button onClick={ this._handleButtonClick.bind(this) }>
  2. click me
  3. </button>

但是,这样做的话 bind 函数会一次又一次地被调用,这是因为 button 可能会渲染多次。一种更好的方式是在组件的构造函数中来创建绑定:

  1. class Switcher extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = { name: 'React in patterns' };
  5. this._buttonClick = this._handleButtonClick.bind(this);
  6. }
  7. render() {
  8. return (
  9. <button onClick={ this._buttonClick }>
  10. click me
  11. </button>
  12. );
  13. }
  14. _handleButtonClick() {
  15. console.log(`Button is clicked inside ${ this.state.name }`);
  16. }
  17. };

附带一提,在处理函数需要和组件的上下文保持统一时,Facebook 推荐 的也是此技巧。

构造函数还是部分执行处理函数的好地方。例如,我们有一个表单,但是不想为每个 input 提供一个单独的处理函数。

  1. class Form extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this._onNameChanged = this._onFieldChange.bind(this, 'name');
  5. this._onPasswordChanged =
  6. this._onFieldChange.bind(this, 'password');
  7. }
  8. render() {
  9. return (
  10. <form>
  11. <input onChange={ this._onNameChanged } />
  12. <input onChange={ this._onPasswordChanged } />
  13. </form>
  14. );
  15. }
  16. _onFieldChange(field, event) {
  17. console.log(`${ field } changed to ${ event.target.value }`);
  18. }
  19. };

结语

对于 React 中的事件处理,其实没有太多需要学习的。React 的作者们在保留开发者的使用习惯上做的十分出色。因为 JSX 使用的是类似 HTML 的语法,所以使用类似 DOM 的事件处理意义重大。