React ES6, How to keep decorators in separate files

362 Views Asked by At

We have created lots decorator in ReactApp.

Now we have to write decorators in every file, My typical Code look something like this.

******** MyComponent.js *************

import {Decorators} from 'decoratorLib';
import React, {Component} from 'react';

const {ModuleLoader, ModuleConfig, log} = Decorators;

@ModuleLoader({
    config: {
        k1: 'Value 1',
        k2: 'Value 2',
        viewClass: ModuleViewClass,
        ...moduleConfig
    },

    propTypes: {
        name: PropTypes.string.isRequired,
        age: PropTypes.number,
        address: PropTypes.string,
        quantity: PropTypes.number
    }
})

@ModuleConfig({
    config: {
        k1: 'Value 1',
        k2: 'Value 2',
        viewClass: ModuleViewClass,
        ...moduleConfig
    }
})

@log({
    config: {
        warning: true,
        error: true,
        breakOnError:false
    }
})
class MyComponent extends Component {

}

I am wondering How, we can write these decorators in a sperate file and then write some bridge to pass/connect with classes

Like I can have a decorators.js file, write all decorators here and then write some method or injector to inject these in classes.

2

There are 2 best solutions below

0
On BEST ANSWER

Decorators are just values, so you can change your code to

const loaderDecorator = ModuleLoader({
    config: {
        k1: 'Value 1',
        k2: 'Value 2',
        viewClass: ModuleViewClass,
        ...moduleConfig
    },

    propTypes: {
        name: PropTypes.string.isRequired,
        age: PropTypes.number,
        address: PropTypes.string,
        quantity: PropTypes.number
    }
});

const configDecorator = ModuleConfig({
    config: {
        k1: 'Value 1',
        k2: 'Value 2',
        viewClass: ModuleViewClass,
        ...moduleConfig
    }
});

const logDecorator = log({
    config: {
        warning: true,
        error: true,
        breakOnError:false
    }
});

@loaderDecorator
@configDecorator
@logDecorator
class MyComponent extends Component { }

and at that point you're free to move those variables to any file you want, then import them into this file to use them, e.g.

import { loaderDecorator, configDecorator, logDecorator } from './my-decorators';

@loaderDecorator
@configDecorator
@logDecorator
class MyComponent extends Component { }

with

export const loaderDecorator = ModuleLoader({
    config: {
        k1: 'Value 1',
        k2: 'Value 2',
        viewClass: ModuleViewClass,
        ...moduleConfig
    },

    propTypes: {
        name: PropTypes.string.isRequired,
        age: PropTypes.number,
        address: PropTypes.string,
        quantity: PropTypes.number
    }
});

export const configDecorator = ModuleConfig({
    config: {
        k1: 'Value 1',
        k2: 'Value 2',
        viewClass: ModuleViewClass,
        ...moduleConfig
    }
});

export const logDecorator = log({
    config: {
        warning: true,
        error: true,
        breakOnError:false
    }
});
2
On

Decorator is actually a function

@decorator1(args)
@decorator2(args)
class Decorated {}

is just function composition and application

Decorated = decorator1(args)(decorator2(args)(Decorated))

So you could compose all your decorators beforehand

// decorators.js
const compose = (fns...) => init => fns.reduceRight((res, fn) => fn(res), init)

export default compose(
    ModuleLoader({
        config: {
            k1: 'Value 1',
            k2: 'Value 2',
            viewClass: ModuleViewClass,
            ...moduleConfig
        },

        propTypes: {
            name: PropTypes.string.isRequired,
            age: PropTypes.number,
            address: PropTypes.string,
            quantity: PropTypes.number
        }
    }),
    ModuleConfig({
        config: {
            k1: 'Value 1',
            k2: 'Value 2',
            viewClass: ModuleViewClass,
            ...moduleConfig
        }
    }),
    log({
        config: {
            warning: true,
            error: true,
            breakOnError: false
        }
    })
)

and then just

import decorate from './decorators'

@decorate
class MyComponent extends Component {

}