Pull to refresh

Comments 31

Так и не понял, что хотел сказать автор оригинала. Зачем он переходил с Ember на React? Если у первого всё так замечательно, развитая экосистема и работа из коробки?..

Похоже весь пост создан ради «прикольный джифок», а между ними вода.

Поддержу тему анимации. "Гифки" доставили больше, чем сама статья:D

Гифок было бы достаточно с заголовками )
Окей, тема про TS и React :) А давайте обсудим такой момент.

Как вы делаете dependency injection в React-компоненты? Или как обходитесь без него, не создавая сильных связей? Передаете по цепочке с корня? Контексты? Какие-то сторонние библиотеки?
dependency injection
import Blabla from 'blabla'; // это не сложно

Котекст = redux

Компоненты есть тупые и есть умные (работают с контекстом напрямую, сами ничего не рисуют а только передают данные в тупые компоненты), т.о. цепочки компонентов очень короткие
Вот «import Blabla from 'blabla'» и хочется избежать — за исключением того случая, когда blabla — это blabla.ts.d с интерфейсом. Dependency inversion principle, вот это всё.
Это нормально :) Меня не то что напрягает (хотя есть немного), но больше для конкретной практической цели нужна отвязка от реализации.

Будем считать, что вопрос адресован тем, кого напрягает. :)
Это и есть отвязка от реализации, просто вместо DI в конструкторе, через модули и явно. А в импортируемом модуле может быть уже что угодно — фабрика, синглтон и т.д.
А если вас волнуют тесты, то «require» в nodejs mock-ается, а в https://facebook.github.io/jest/ из коробки.

Но я когда-то делал DI для React и через свойства класса и через конструктор, очевидно, что для этого пришлось подменять React.createElement. И это тоже нормально, но, в итоге, импорты победили.
Да понятно, просто с require получается аналог не DI, а сервис-локатора. А хочется именно DI.
Ну, начнем с того, что React вообще по идеологии закрыт от изменения компонента таким путем, в аргументах конструктора у него props, а свойства нельзя назначать снаружи. А все инициализации должны происходить в соответствующем этапе lifecycle. Например, в componentWillMount. Следовательно, получение там экземпляра нужного объекта хоть и не является классическим решением DI, но, принципиально ничем не отличается. Мы можем, через модули, все так же запрашивать именно этот класс, а не получать ссылку на ServiceLocator.
//component1.js

import Inject1 from './inject1';


componentWillMount(){
this.inject1 = Inject1();
}

//inject1.js
export default ()=>{
return new Inject1(params);
}

По-моему, это вопрос синтаксиса, а не паттернов.
DI — push подход
Service Locator — pull подход
У вас компонент сам тянет свои зависимости = Service Locator
Service Locator — вполне конкретный паттерн, характеризующийся созданием одного контейнера для всех объектов и содержащий ссылки на все инъекции. В моем примере такого контейнера нет.
Просто, в случае Java и C# — внедрение зависимости происходит только через класс, а в случае nodejs — через модуль + класс.

Сможете объяснить разницу в применении?
constructor(inject1: Inject1){
}
и
import Inject1 from './inject1';
constructor(){
this.inject1 = Inject1();
}
допустим у нас есть модуль inject2, который содержит Inject2 и его интерфейс совместим с Inject1
если мы захотим иметь несколько инстансов компонента с разными inject'ами
первый вариант этому не воспрепятствует
в отличии от второго

может вы расскажите, как такие ситуации разруливаются в мире nodejs?
Точно так же, как в любом другом мире
//inject1.js — модуль, являющийся частью DIC, а не классом Inject1!!!
export default ()=>{
if (ХОЧУ1){
return new Inject1(params);
}else{
return new Inject2(params);
}
}
Повторюсь, я не изобрел велосипед, это всего лишь вопрос синтаксиса.

К слову, в nodejs и typescript, в частности, нет некоторых возможностей, например, деструктора, в связи с чем нельзя вручную удалить созданную зависимость, приходится играться с GC. А также, нет рефлексии, это частично решается декораторами.
Но ведь тогда все должны ссылаться явно на модуль, инициализирующий все это добро (собственно, контейнер), чего хотелось бы избежать и получать все инстансы неявно.
Кажется, что достичь этого можно малой кровью, декорируя поля на классе либо через мета-данные TS, либо через символы, импортируемые из модулей, содержащих нужные классы.
В принципе все это достаточно просто делается через react-контекст, создаваемый компонентом-провайдером конфигурации контейнера. А компоненты, которым нужны инстансы, декорируются с простановкой contextTypes и т.п. Там же можно вклиниться в componentWillUnmount и поубивать все инстансы.
С другой стороны, возникает закономерный вопрос, на кой это все, если redux-экшенов для ui-слоя должно хватить с лихвой? Экшены, конечно, уже могут инжектить инстансы каких-либо сервисов.
Нет, мы ссылаемся не на контейнер и не на конкретный instance, а просто с помощью import — объявляем мета-данные модуля, точно так же, как и любым другим способом (которые вы перечислили относительно класса). Почему вы хотите этого избежать? DI нужен для unit-тестирования и композиции, этот способ прекрасно подходит для этого (я описал выше).
А для React-компонентов DI бывает нужен для внешних UI-библиотек, ну и, видимо, для противников чистых функций.
Вот теперь сижу и думаю, а ведь действительно, почему? Видимо, дело привычки отделять дизайнтайм от рантайма. Этакое «ожидание DOMContentLoaded». Да и нежелание мокать require в ноде — видимо, тоже.
Вы выше написали, что, при разработке DI с помощью разных подходов, импорты в итоге победели. Можете объяснить почему? Какие значимые плюсы по сравнению с классическим подходом?

Про UI-либы для реакта не понял, там же просто классы лежат, зачем их вставлять через DI? Тут-то как раз импорты подходят.
Да, дело именно в разных подходах к файлам и импорту.
Мокать тоже не обязательно, есть и другие способы, в DI-контейнере вставлять условие NODE_ENV, например. Для модуля опять же подмена произойдет неявно.

Плюсы исходят из «недостатков-фич» nodejs, я описал их, в C# мы можем внедрять зависимость по типу, в JS такой возможности вообще нет, поэтому классический подход невозможен. Способ же Angular 1 — для меня является худшим примером, каждый контроллер знает именно об этом сервисе, а не об интерфейсе. Мы не можем подменить сервис в одном контроллере на другой, мы не можем переименовать сервис, все сильно связано со всем.
Если же говорить про TypeScript, то, во-первых, способ через декораторы означает повторное объявление типов, рефлексия в зачаточном состоянии.
Да и вопрос, должны ли классы, а не модули в NodeJS быть unit-ами открыт, несмотря на давление со стороны Java-сообщества (Google, в частности).

По поводу, UI-либ, ну по той же причине, что и любой DI — неявное создание экземпляров или синглтоны. Допустим, есть некий сложный компонент на JQuery UI, требующий сложной инициализации, но который нужно вставлять в разные React-компоненты.
В свежем typescript достаточно декоратора с произвольным именем (скажем, Inject) — уже будут сгенерированны метаданные с необходимой информацией. В aurelia так сделано, например. А в angular2 обычно используется побочный эффект — декоратор Component уже есть.

Со способом angular1 все нормально (настолько, насколько нормально можно сделать в рамках ES5), просто его часто неправильно используют. Надо писать не module.service('Foo', пошла_пачка_кода...), а module.service('Foo', SomeFooImplementation), и рассматривать определение модуля как конфигурацию контейнера.
ок, а условие «ХОЧУ1» откуда берётся?
По цепочке, постепенно разыменовывая при каждой возможности.
Мы для этих целей сделали свой микрофреймворк — intakejs.
В ближайшее время готовим к нему нормальную документацию, а потом и статью напишем.
Каждая статья сравнение заканчивается тем, что «чем пользоваться выбирайте сами, всё хорошо»
Не смог прочитать пост из-за постоянного мельтешения.
Поясните, пожалуйста, что не так с документацией по Ангуляру? Есть пошаговый гайд, есть описание для разработки директив/сервисов и есть описание API. Мне в свое время этого хватило с головой для старта.
Признаюсь, вначале пути от «вёрстки до JS» я тоже пошел в документацию к Angular и не смог разобраться достаточно, чтобы решить поставленную в тот момент задачу. Но уже через пол года «иероглифы» превратились в понятные буквы и документация показать вполне вменяемой. На мой взгляд это вопрос уровня понимания и качества восприятия.
Например, документация по Директивам — пример ОЧЕНЬ плохой документации для неподготовленного.
Кто-нибудь на данный момент использует React без Flux и есть ли стоящие альтернативы как таковые?

А по теме поста, увы, нечего прокомментировать, но стало понятно, что по мнению автора документация Angular 2 сложнее документации Ember, у которого в коробке инструментов есть много дополнительных «плюшек». А React – это библиотека, не фреймворк и JSX не так уж плох. Спасибо!
Сама суть реакта подразумевает парадигму flux — данные вниз, действия вверх (или «в бок» для экшенов). Сам не пробовал, но вроде MobX набирает обороты.
Sign up to leave a comment.