2016-10-15 10 views
0

ミックスインが悪いことを読んだら、自分で悪い経験をした後、ミックスインでのコンポジションを再利用するためにコードをリファクタリングしたい。ミックスインと組成リファクタの比較

イベントを発生させてスタイリングできるようにしたい。イベントを操作する関数を含むmixin EventEmitterと、スタイリングを操作する関数を含むStylableがあります。

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

私はこのようなStyleableと持つEventEmitterのためのコンポーネントを作成しようとしました::

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

しかし、私はないミックスインで

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

は、例えば、コンポーネントは、次のようになります。正しく使用する方法を知っている。私はこれらのコンポーネントをラッパーとして使用する必要があることを読んだが、これを達成する方法はわからない。上記の例のレンダリング関数のようにしてみました。 mixinのような機能を持つボタンをどうやってインスタンス化できますか?

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

それとも私が組成物からの間違った行動を期待しています:私はちょうどこのように必要なfunctionalitysを渡すように?

答えて

1

基本的には、新しいコンポーネントを返す関数を作成する必要があります。あなたの持つ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> 
 
    ) 
 
    } 
 
}

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} 
 
     /> 
 
    ); 
 
    } 
 
    } 
 
}

がそれを使用するには、あなたはこのような何かをしたいです

最後に、あなたのボタンの中に、あなたは小道具からのイベント・エミッターへのアクセス権を持っていると思います:

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メソッドがあることを知る必要はありません)。イベントエミッタの動作方法を変更すると、 "ダム"アップデートするコンポーネント)。

この臭いを修正するには、ユースケースについてもっと知る必要がありますが、eventEmitterWrapper関数が返すクラスを単純な具体的なメソッド(「emitEvent」などマウス/キーボードイベントの1つの引数)

高次コンポーネントを使用する方法を説明してください。

追加読書:

+0

私はそれをリファクタリングしようとした理由があり、与えられたソースを読みました。 EventEmitterのように、追加したい機能が1つしかない場合はうまく動作します。しかし、もし私がStyleableを追加したいのであれば、私は 'styleableWrapper'のようなチェーンを持っています。私はあなたがポイントを得ることを願っています。また、 'eventEmitterWrapper'で宣言された関数にアクセスすることもできません。 – landunder

+0

上位コンポーネントは上位コンポーネントをラップできます。それはまったく臭いではありません(それは単なる機能構成です!)。相互依存関係がない限り、私は思うに、 'styleableWrapper'が' eventEmitterWrapper'に依存すれば少し臭くなりますが、そのようには聞こえません。 –

+0

'eventEmitterWrapper'で宣言された関数にアクセスできないというあなたのコメントのためには、それらをpropsとして渡す必要があります。各HOCはすべての委任された小道具を通過しているので、渡したものは '{... this.props} 'によって集められます。 –

関連する問題