В объектно-ориентированном программировании шаблон декоратора - это шаблон проектирования, который позволяет статически или динамически добавлять поведение к отдельному объекту, не влияя на поведение других объектов из того же класса. Он помогает решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторно использовать. (Источник: Википедия)
Проще говоря, декораторы - это синтаксический сахар, помогающий вам сохранять ваш код читаемым и поддерживаемым, путем обертывания дополнительных или общих функций в отдельном файле, который может совместно использоваться разными компонентами / классами. Концепция декораторов была впервые представлена в python, а сейчас они также становятся частью javascript.
ПРИМЕЧАНИЕ. Декораторы представляют собой предложение этапа 2 для JavaScript и доступны в качестве экспериментальной функции TypeScript. Декораторы - это экспериментальная функция, которая может измениться в будущих выпусках.
Что, почему и как используют декораторы в React:
Декораторы в React помогают вам взять существующий компонент класса или функцию компонента класса и изменить его, тем самым позволяя добавлять дополнительные возможности без необходимости возиться с существующей базой кода. Модификация может полностью переопределить существующую функцию или просто добавить к ней дополнительную логику. По сути, декораторы берут одну функцию и возвращают другую после ее приправки. Реагирование и декораторы могут идти рука об руку благодаря наличию компонентов высшего порядка и функций высшего порядка.
Давайте посмотрим на один пример декоратора функции / метода:
function deprecatedFn(target, name, descriptor) { const newDescriptor = { ...descriptor }; const originalFunction = descriptor.value; function deprecatedFunctionWarning(args) { originalFunction.call(this, ...args); if(__DEV__) { console.warn("This function is about to be Deprecated"); } } newDescriptor.value = deprecatedFunctionWarning; return newDescriptor; } class SomeOldCodeBaseClass extends React.Component { @deprecatedFn someFunction() { // Some deprecated logic } }
Приведенный выше код предупреждает разработчиков об использовании устаревшей функции, не прерывая поток данных устаревшей функции. Давайте углубимся в то, что происходит на самом деле:
deprecatedFn
: декоратор функции (т. Е. Переопределение функции / метода класса), имеет 3 аргумента: цель, имя и дескриптор.- target: класс, частью которого является свойство / функция / метод. (в нашем случае
SomeOldCodeBaseClass
) - name: имя свойства / функции / метода, переопределяемого декоратором. (в нашем случае
someFunction
) - дескриптор: дескриптор свойства, аналогичный объекту, переданному в Object.defineProperty (но не то же самое). Он имеет логические значения, такие как
enumerable, configurable, value, writable
- descriptor.value: Он ссылается на функцию, к которой применяется декоратор. (здесь
someFunction
) - Мы пишем другую функцию, которая вызывает исходную функцию (т.е.
someFunction
) с помощью метода call. Вы можете избавиться от call, если исходная функция не требует контекста this. - Наконец, мы назначаем дескриптору вновь созданную функцию, а затем возвращаем новый дескриптор. Теперь, когда React вызывает
someFunction
, управление переходит к нашему декоратору, который, в свою очередь, возвращает замещенную функцию.
Теперь посмотрим, как работают декораторы классов:
export default Child => { class GetExtraDataInProps extends React.Component { someHelperFunction() { // some logic here } render() { const data = { // some dummy data }; return <Child {...this.props} callbackFn={someHelperFunction} extraData={data} />; } } return GetExtraDataInProps; }; @GetExtraDataInProps export default class HelloWorld extends React.Component { ... }
Декоратор классов очень похож на наши React HOC, то есть оба принимают компонент в качестве входных данных и возвращают компонент таким же образом. Помимо синтаксических различий, давайте поговорим о производительности.
Я использовал react-addons-perf
, чтобы сравнить два, где HOC и декоратор имели один и тот же код, единственная разница заключалась в том, как они связаны с Компонентом. Декораторы располагаются поверх Component при объявлении, тогда как HOC упаковываются, пока вы хотите их экспортировать. Я обнаружил, что HOC работают лучше, чем декораторы, поскольку время рендеринга HOC было быстрее, чем у класса декоратора.
Примечание. Производительность рассчитывалась с использованием
Perf.start()
передsetState()
иPerf.end()
внутриcomponentDidUpdate()
.
Настройка декораторов для вашего проекта:
Поскольку декораторы являются экспериментальной функцией в Typescript, они не являются частью вашей конфигурации Babel по умолчанию, поэтому ваш сборщик выдаст синтаксическую ошибку. Чтобы ваш бандлер был совместим с декораторами, включите плагин babel в свой devDependencies
внутри package.json
, или вы можете добавить плагин в свой babel.rc
файл:
"@babel/plugin-proposal-decorators": "^7.3.0"
Чтобы автоматически привязать (привязать функции внутри класса к контексту класса) методы класса к вашим декораторам класса, включите следующее в свой dependencies
внутри package.json
:
"class-autobind-decorator": "^3.0.1"
Вывод:
Декораторы могут быть мощным шаблоном проектирования кода, позволяющим писать более чистые и удобные в обслуживании компоненты React, однако я все же рекомендую HOC вместо декораторов классов. Поскольку декораторы все еще находятся на стадии 2 предложения ECMA, они могут меняться со временем, поэтому используйте их с умом.
В будущем мы обсудим, как OYO использовала шаблон декоратора для масштабирования и включила постоянно растущие варианты использования магазинов OYO, минимизируя усилия разработчиков и упрощая кодовую базу.
Использованная литература: