React将所有事件传递给子组件

时间:2016-09-08 20:50:50

标签: javascript reactjs

React是否可以将所有事件传递给子元素。

作为一个例子我有一个自定义Button类,(简化)看起来像这样:

class Button extends Component {
  
  constructor (props) {
    super(props);

    this.onClick      = this.onClick.bind(this);
  }
  
  /* .... */
  
  onClick (ev) {
    const { disabled, onClick } = this.props;
    if (!disabled) {
      onClick(ev);
    }
  }
  
  render () {
     const {
      children,
      disabled,
      type
     } = this.props;
    
    return (
      <button
        disabled={disabled}
        onClick={this.onClick}
        ref="button"
        type={type}
      >{children}</button>
  }
  
  
}

我不知道将来我想要使用哪些事件(onMouseDown,onMouseUp,onBlur,onKeyDown,onTouchStart等等)

是否可以将所有可能的事件传递给按钮元素,而无需为每个可能的事件写出道具?

将<... this.props}添加到按钮元素不是我想要的,因为它传递了所有道具,并且不应直接传递一些道具(如本例中省略的className)。

我想克隆道具对象并删除不应该直接传递的道具,但这感觉就像一个黑客。有人知道更干净的方式吗?

1 个答案:

答案 0 :(得分:2)

我编写了一个迭代道具的函数,并过滤掉所有以'on'开头的属性,这是我到目前为止最接近的。万一它可以帮助其他人:

/* helpers.js */

export function filterEvents (props, ignore = []) {
  let events = {};
  for (let property in props) {
    if (props.hasOwnProperty(property)) {
      if (property.startsWith('on') && ignore.indexOf(property) === -1) {
        events[property] = props[property];
      }
    }
  }

  return events;
}

/* Tests for the filterEvents */
  
import { expect } from 'chai';

import { filterEvents } from './helpers';

describe('filterEvents', () => {

  const props = {
    className: 'someClass',
    disabled: true,
    onBlur: 'onBlur',
    onClick: 'onClick',
    onMouseDown: 'onMouseDown',
    onMouseUp: 'onMouseUp'
  };

  it('only returns keys starting with on', () => {
    const expected = {
      onBlur: 'onBlur',
      onClick: 'onClick',
      onMouseDown: 'onMouseDown',
      onMouseUp: 'onMouseUp'
    };

    expect(filterEvents(props)).to.deep.equal(expected);
  });

  it('only returns keys starting with on minus the ones in the ignore array', () => {
    const expected = {
      onBlur: 'onBlur',
      onMouseUp: 'onMouseUp'
    };

    const ignore = ['onClick', 'onMouseDown'];
    expect(filterEvents(props, ignore)).to.deep.equal(expected);
  });

});


/* Using the function inside a component */

import { filterEvents } from './helpers'; //at the top of the components file

//Inside the render method:

const events = filterEvents(this.props, ['onClick']); //don't include onClick it's handled like the questions example

return (
  <button
    disabled={this.props.disabled}
    onClick={this.onClick}
    {...events}
  >
    {this.props.children}
  </button>
);

相关问题