(псевдо)Наследование для компонентов ReactJS
Я хочу написать коротенький пост, про то, как я решил проблему наследования в ReactJS. Обычно, на форумах, люди советуют использовать миксины для наследования функционала, но, по-моему, это не совсем правильно. Все-таки трэйты/миксины и классы это не одно и то же, да еще и из-за возможности множественного наследования могут возникать вот такие казусы: var A = { doStuff (){} }
var B = { doStuff (){} }
var C = React.createClass ({ mixins: [A, B] }); //упс… ошибка, потому что React не может решить какой из doStuff унаследовать К тому же, миксины не позволяют делать стандартные ООПешные фишки вроде перезаписи методов (method override):
var A = { doStuff (){} }
var C = React.createClass ({ mixins: [A], doStuff (){ //неа, не получится } }); А без этого, естественно, не сработает и расширение функционала как во «взрослых» ООП языках:
doStuff (){ super.doStuff () //дополнительный функционал } Конечно, классы ES6 решат эту проблему, и команда ReactJS к этому готовится, если судить по постам на их блоге, но ждать ES6 придется как второго пришествия, а затем, придется еще подождать пока не вымрут старые Интернет Эксплореры без поддержки ES6.Итак, я хочу предложить вам альтернативный метод, который и сам использую, но для этого вам понадобятся:1) Система модулей/зависимостей: RequireJS/Browserify/WebPack/что там еще сейчас в моде. Если вы не пользуетесь/не знаете что такое JavaScript модули, что ж, самое время узнать.2) Какая-нибудь функция/либа для глубокого копирования объектов, например, jQuery.extend, _.extend и т.п.
Итак, я пишу модули своих компонент следующим образом:
var React = require ('react'); var Human = { whoAreYou (){ return «I’m a human»; }
whatDoYouDo (){ return «I’m just chilling»; }
render (){ return (
{this.whoAreYou ()}{this.whatDoYouDo ()}
) } }module.exports = {
Class: Human,
Component: React.createClass (Human)
}
Фишка в том, что я экспортирую не только компоненту, но и «чистый» объект, из которого эта компонента создается, таким образом, когда мне надо использовать просто компоненту
var Human = require ('human').Component; А вот когда мне надо от моего модуля унаследовать, и тут начинается самое интересное, я использую поле Class:
var React = require ('react'); var Parent = require ('human').Class; var Programmer = {}; jQuery.extend (true, Programmer, Parent, { whoAreYou (){ return Parent.whoAreYou.apply (this) + » and a programmer»;//вызов метода из родителя! } whatDoYouDo (){ //перезапись метода полностью return «I write code»; }
drinkCoffee (){ //добавление нового метода console.log ('*sip*'); } }); Естественно, этот модуль я тоже экспортирую согласно вышеописанной «конвенции»:
module.exports = { Class: Programmer, Component: React.createClass (Programmer) } И теперь его можно использовать в приложении:
var Programmer = require ('programmer').Component; Ну, или наследовать/расширять дальше, например, в JuniorDeveloper.И на этом все, это был мой коротенький пост про костыль для (псевдо)наследования в ReactJS. Успешной вам трудовой недели, господа!