反应mixin到组合重构

时间:2016-10-15 11:24:42

标签: javascript reactjs

在我阅读了mixins有多糟糕并且自己做了一些不好的经历之后,我想重构我的代码以使用mixin来实现可重用性。

我想要一个组件来发出事件并且可以设置样式。所以我有mixins EventEmitter,它包含操作事件的函数和包含操作样式的函数的Stylable。

var Styleable = {
  addStyleProperty: function(styleProperty) {
     ...
  },
  ... 
};
var EventEmitter = {
   addEventListener: function(eventName, func) {
   },
   ...
};

使用mixins,示例组件如下所示:

var Button = React.createClass({
  mixins = [EventEmitter, Styleable],
  ...
});

使用合成我尝试为Styleable和EventEmitter创建组件,如下所示:

var StylableComponent = React.createClass({
  addStyleProperty: ...
  render: function() {
    React.createElement(this.props.wrappedComponent, ...)??
  }
}
var EventEmitterComponent = ...

但我不知道如何正确使用它们。我读到我必须使用这些组件作为包装器,但我不知道如何实现这一点。我试着像上面例子的渲染函数那样做。如何实现具有与mixin变体类似的功能的按钮?所以我只是传递了所需的功能:

<Button is={[StyleableComponent, EventEmitterComponent]}/> 

或者我期待作曲的错误行为?

1 个答案:

答案 0 :(得分:1)

基本上,您希望创建一个返回全新组件的函数。

例如,对于您的EventEmitter,它看起来像这样:

import eventEmitter from 'your-event-emitter-location';

// This function takes a component as an argument, and returns a component.
function eventEmitterWrapper(ComposedComponent) {
  // This is the brand new "wrapper" component we're creating:
  return class extends Component {
    render() {
      // We want to return the supplied component, with all of its supplied
      // props, but we also want to "add in" our additional behaviour.
      return (
        <ComposedComponent
          {...this.props}
          eventEmitter={eventEmitter}
        />
      );
    }
  }
}

要使用它,你可以这样做:

import Button from '../Button';
import eventEmitterWrapper from '../../HOCs/event-emitter';

class Home extends Component {
  render() {
    const EventEmitterButton = eventEmitterWrapper(Button);

    return (
      <div>
        <EventEmitterButton onClick={doSomething}>
          Hello there!
        </EventEmitterButton>
      </div>
    )
  }
}

最后,在你的按钮中,你可以从道具中访问事件发射器:

const Button = ({ children, onClick, eventEmitter }) => {
  // Let's say, for example, you want to emit an event whenever the
  // button is clicked. You could do something like this:
  const clickHandler = (ev) => {
    onClick(ev);
    
    if (eventEmitter) {
      eventEmitter.emit('click', ev);
    }
  };
  
  return (
    <button onClick={clickHandler}>
      {children}
    <button>
      
  )
}

注意:这是一个人为的例子。这种模式对我来说有点臭; Button对事件发射器的内部工作方式了解得太多(例如,它不需要知道它有emit方法。如果你改变了事件发射器的工作方式,你就是' d有一堆“哑”组件要更新。

为了解决这个问题,我需要了解更多关于你的用例的信息,但我可能会让eventEmitterWrapper函数返回的类暴露出简单的特定方法(例如“emitEvent”,这将采用鼠标/键盘事件的单个参数)

希望它说明了如何使用更高阶的组件!

补充阅读: