I've been reading up on decorators in JavaScript, and think I'm getting the basic premise.
Decorators are functions, they receive as a or several parameters what they should decorate, and return the result.
But I came over a @withStyles
decorated implementation in a React Boiler Plate project which I do not understand how works.
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;
A use case would be
import s from './MyComponentStyle.scss';
@withStyles(s)
class MyComponent extends Component {
}
How does this work?
A Python class decorator adds a class to a function, and it can be achieved without modifying the source code. For example, a function can be decorated with a class that can accept arguments or with a class that can accept no arguments.
The whole purpose of Angular decorators is to store metadata about a class, method, or property. When you configure a component, you are providing a metadata for that class that tells Angular that you have a component, and that component has a specific configuration.
They are used to enhance the functionality of the function without modifying the underlying function. They are just modifying the behavior of the function or method passed to it by returning a new function. Decorators have already been used in languages like Python and C#, now it is used in JavaScript also.
A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression , where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.
Class decorators can be used as factory functions. For Example:
function myDecorator(value) {
return function(target) {
target.myProperty = value;
}
}
@myDecorator('myValue')
class MyClass { }
In your example the factory function returns constructor function which wraps original class. This function is used to create object instead of the original class. In your case it handles events (componentWillMount
, componentWillUnmount
) in order to insert/remove css and renders the original component with it's props.
This is very simple example demonstrating how is the original constructor function overrided by decorator:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With