2016-01-13 15 views
9

Ho letto i decoratori in JavaScript e penso di avere le premesse di base.Decoratori di classe in ES7

I decoratori sono funzioni, ricevono come o più parametri ciò che devono decorare e restituiscono il risultato.

Ma mi sono imbattuto in un'implementazione decorata @withStyles in un progetto React Boiler Plate che non capisco come funziona.

import React, { Component, PropTypes } from 'react'; 

function withStyles(...styles) { 
    return (BaseComponent) => class StyledComponent extends Component { 
    static contextTypes = { 
     insertCss: PropTypes.func.isRequired, 
    }; 

    componentWillMount() { 
     this.removeCss = this.context.insertCss.apply(undefined, styles); 
    } 

    componentWillUnmount() { 
     this.removeCss(); 
    } 

    render() { 
     return <BaseComponent {...this.props} />; 
    } 
    }; 
} 

export default withStyles; 

Un caso d'uso sarebbe

import s from './MyComponentStyle.scss'; 

@withStyles(s) 
class MyComponent extends Component { 

} 

Come funziona?

risposta

13

I decoratori di classe possono essere utilizzati come funzioni di fabbrica. Ad esempio:

function myDecorator(value) { 
    return function(target) { 
     target.myProperty = value; 
    } 
} 

@myDecorator('myValue') 
class MyClass { } 

Nell'esempio la funzione di fabbrica restituisce la funzione di costruzione che include la classe originale. Questa funzione è utilizzata per creare oggetti al posto della classe originale. Nel tuo caso gestisce gli eventi (componentWillMount, componentWillUnmount) per inserire/rimuovere css e renderizza il componente originale con i suoi oggetti di scena.

Questo è molto semplice esempio che illustra come è la funzione di costruzione originale annullate dagli decoratore:

function myDecorator(name) { 
    return (target) => class Wrapper { 
     sayHello() { 
      const targetObject = new target(); 
      console.log(`wrapper ${name} says hello`); 
      targetObject.sayHello(); 
     } 
     wrapperMethod() { 
      console.log('calling wrapper function'); 
     } 
    }; 
} 

@myDecorator('Jack') 
class MyClass { 
    sayHello() { 
     console.log('original says hello'); 
    } 
    myMethod() { 
     console.log('calling original function'); 
    } 
} 

var obj = new MyClass(); 

obj.sayHello(); 
//wrapper Jack says hello 
//original says hello 

obj.wrapperMethod(); 
//calling wrapper function 

obj.myMethod(); 
//TypeError: obj.myMethod is not a function