2016-10-15 4 views
0

Nachdem ich gelesen habe, wie schlecht Mixins sind und machte einige schlechte Erfahrungen von mir, möchte ich meinen Code Refactor, um Zusammensetzung über Mixins zu verwenden, um Wiederverwendbarkeit zu erreichen.Reagieren Mixin zu Zusammensetzung Refactor

Ich möchte eine Komponente, um Ereignisse zu emittieren und stylable zu sein. Also habe ich die Mixins EventEmitter, die Funktionen zur Manipulation der Ereignisse und Stylable enthält, die Funktionen enthält, um das Styling zu manipulieren.

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

Mit Mixins ein Beispiel Komponente sieht wie folgt aus:

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

Mit Komposition Ich habe versucht, wie diese erstellen Komponenten für Styleable und EventEmitter:

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

Aber ich nicht weiß, wie man sie richtig benutzt. Ich habe gelesen, dass ich diese Komponenten als Wrapper verwenden muss, aber ich weiß nicht, wie ich das erreichen soll. Ich habe versucht, es in der Render-Funktion des obigen Beispiels zu tun. Wie kann ich einen Button instanziieren, der genau wie die Mixin-Variante funktioniert? So dass ich nur die erforderlichen Funktionen wie folgt übergeben:

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

Oder erwarte ich ein falsches Verhalten von Zusammensetzung?

Antwort

1

Im Wesentlichen möchten Sie eine Funktion erstellen, die eine brandneue Komponente zurückgibt.

Für Ihre EventEmitter, zum Beispiel, ist es in etwa so aussehen würde:

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

, es zu benutzen, würden Sie so etwas tun:

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

schließlich in Ihrer Taste, dann würden Sie Zugriff auf Ereignis-Emitter aus den Requisiten:

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

HINWEIS: Dies ist ein konstruiertes Beispiel. Dieses Muster ist ein wenig stinkend für mich; Die Button weiß zu viel über die interne Funktionsweise des Event-Emitters (Es sollte nicht wissen, dass es eine emit-Methode zum Beispiel hat. Wenn Sie ändern, wie Ihr Event-Emitter funktioniert, hätten Sie eine Menge "dumm" zu aktualisierende Komponenten).

Um diesen Geruch zu beheben, müsste ich mehr über Ihren Anwendungsfall wissen, aber ich würde wahrscheinlich die Klasse durch die eventEmitterWrapper Funktion einfache, spezifische Methoden (wie "emitEvent", die würde erfordern) ein einzelnes Argument der Maus/Tastaturereignis)

Hoffentlich zeigt es, wie man höherwertige Komponenten obwohl verwendet!

Zusätzlicher Lesestoff:

+0

Ich habe die angegebenen Quellen gelesen, deshalb habe ich es zu Refactoring versucht. Es funktioniert gut, wenn es eine Funktionalität gibt, die ich hinzufügen möchte, wie EventEmitter. Wenn ich aber auch das Styleable hinzufügen möchte, habe ich eine Kette wie 'styleableWrapper', die dann die bereits umwickelte Komponente übernimmt, die mir übel riecht. Ich hoffe, Sie verstehen es. Ich habe auch keinen Zugriff mehr auf die Funktionen, die in 'eventEmitterWrapper' deklariert sind. – landunder

+0

Komponenten höherer Ordnung können Komponenten höherer Ordnung umhüllen; es ist überhaupt nicht stinkend (es ist nur Funktion Zusammensetzung!). Ich denke, solange es keine gegenseitigen Abhängigkeiten gibt ... wird es ein bisschen stinken, wenn 'styleableWrapper' von 'eventEmitterWrapper' abhängt, aber das klingt nicht so. –

+0

Für Ihren Kommentar, dass Sie keinen Zugriff auf Funktionen haben, die in 'eventEmitterWrapper' deklariert sind, müssen sie als Requisiten übergeben werden. Da jeder HOC alle delegierten Requisiten übergibt, wird alles, was du passierst, von '{this.props}' gesammelt. –