(псевдо)Наследование для компонентов 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 (               <h1>{this.whoAreYou()}<small>{this.whatDoYouDo()}</small></h1>          )     } }  module.exports = {      Class: Human,      Component: React.createClass(Human) } 

Фишка в том, что я экспортирую не только компоненту, но и «чистый» объект, из которого эта компонента создается, таким образом, когда мне надо использовать просто компоненту <Human/>, я беру поле Component из экспорта моего модуля:

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. Успешной вам трудовой недели, господа!

ссылка на оригинал статьи http://habrahabr.ru/post/247347/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *