Pull to refresh
@Druuread⁠-⁠only

User

Send message
> Еще больше не поверите, использую ngrx/store

Я тоже использую ngrx/store. При этом у меня есть обвязка из (только не пугайтесь)… кастомных декораторов, которая уменьшает типичный редаксовский бойлерплейт в разы ;)
    @Action()
    actionName(
        @Payload("argName") argName,
    ) {
        return { ...this.state, prop: argName };
    }

генерит сразу action-константу, action-creator, метод с вызовом dispatch'a и соответствующий кусок редьюсера. И, да, в отличии от декораторов класса, декораторы аргументов и методов, конечно, уже не просто функции.
> Да потому-что придется копипастить inputs/outputs из my-button в my-button-with-icon.

Инпуты/аутпуты наследуются. У меня же выше был пример с наследованием, там это видно.

> Кастомный декоратор — это сторонние средства.

Декоратор — это _просто функция_. Вот это:
@Component({ ...props })
export class FooComponent {
    
};

ровно то же самое, что и вот это:
class Foo {

};

export const FooComponent = Component({ ...props })(Foo);

Когда вы на реакте применяете какую-то ф-ю к компоненту — вы фактически и используете декоратор :)
//так вы пишите:
const EnhancedComponent = higherOrderComponent(WrappedComponent);

//а можно записать с синтаксисом декоратора:
@higherOrderComponent
export class WrappedComponent {
    
} 

то есть «определить и использовать в реакте HOC» и «определить и использовать кастомный декоратор» — это _одно и то же_. HOC из реакта — это _и есть_ декораторы классов.

> что стандартный Component использовать нельзя, нужно использовать кастомный. И мы возвращаемся к огромному бессмысленному мануалу.

Команда же может запомнить, что надо юзать higherOrderComponent выше? :)

> Окей, тут соглашусь

Значит, по факту декларативности мы вопрос утрясли.
> Ну раз у вас с логикой все в порядке, поведайте миру, чем принципиально HOF отличается от HOC.

Тем, что HOF — это ф-я, которая принимает и возвращает ф-ю, а HOС — это компонент, который принимает и возвращает компонент. Да, реактовские HOС не являются полноценными, я об этом выше уже говорил.

> Сторонними средствами?

Почему сторонними? Вполне нативными.

> Вы что продать пытаетесь? Что разработчик в каждом месте должен писать <with-icon><my-button></my-button></with-icon> вместо <my-button-with-icon></my-button-with-icon>?

Ну так сделайте как в реакте, в чем проблема? Объявите компоненту <my-button-with-icon></my-button-with-icon>, которая будет раскрываться в <with-icon><my-button></my-button></with-icon>. Почему вы не используете реактовские подходы?

> В реакте это упаковывется в компонент и используется без заморочек, что тут надо класс подоткнуть, тут директиву, а тут кастомную разметку.

Потмоу что в реакте это поведение по умолчанию. Если вы захотите какое-то другое поведение — то будет то же самое подтыкание, то тут, то там. В ангуляре другое поведение по умолчанию. Во фреймворке Х — какое-то еще, третье. Это нормально.

> С тем, что это излишнее усложнение.

Вызвать ф-ю — это усложнение? Вы программист, вообще?
У меня, кстати, такой вопрос — а вы используете редакс? Явно нет. Он ведь целиком и полностью состоит из подобных «усложнений», не правда ли?

> Ау. Вы о чем? Я про отсутствие левых декораторов и врапперов.

Функции (они же декораторы) — входят в библиотеку Vanilla JS. Поддерживаются искаробки на всех браузерах и всех устройствах, не требуют импорта, настройки и чего бы то ни было. Какие проблемы? Почему вы используете функции в реакте, но не хотите их использовать в ангуляре?

> Стандартными средствами.

Функции — стандартные средства языка.

> Вы все-равно не видите разницу?

Я вижу разницу, конечно же. В одном случае мы забиваем гвоздь молотком, в другом — вворачиваем шуруп отверткой. Результат практически тот же.

> Уложите <with-icon> и <my-button> в один компонент без наследования.

Почему без наследования-то? :cry:

> Я вам описал проблему, вы проблему не решили.

Вы сказали, что решение на ангуляре недекларативно, я показал декларативное решение. То, что там немного не такой синтаксис как в реакте (или в любом другом фреймворке Х) — ну так это понятно, я здесь не вижу проблемы. Обсуждать религиозные вопросы, еще раз повторю, незачем. Вот был вопрос про декларативность, давайте обсуждать его, а претензии к синтаксису и прочим несущественным вещам — в сторону.

> как с помощью дополнительных конструкций и повышения общей сложности достичь чего-то похожего на решение.

Да я секрет открою, вы можете вообще переопределить Component и импортировать его потом из своего ../utils вместо angular/core. И никто вообще разницы не заметит.

Я, конечно, не предлагаю это как реальное решение — но просто если вам хочется странного такого, то ради бога.
> Вы бы ради приличия в доки хоть заглянули

У вас с логикой какие-то явные проблемы. Из того, что существуют негры, которые являются людьми, следует ли, что люди — это негры? Нет. Точно так же и из того, что существуют функции, которые являются компонентами, не следует, что компоненты — это функции.

> Уже же вроде обсудили, не наследуется конфигурация.

Вам никто не мешает наследовать, если хотите.

> при попытке спрятать этот темплейт в компонент, вам придется руками прокидывать все возможные inputs/outputs до кнопки.

Вы же таскаете с собой эту конструкцию каждый раз, когда дергаете фунарги? Или вы в выборе из двух вариантов:
function f(x: number, y: number) {
  return x+y;
}

function g1(z: number, x: number, y: number) {
  return f(x, y) + z;
}

function g2(z: number, ...args: number[]) {
  return f.apply(args) + z;
}

вы выбираете g2? Мы тут не договоримся, потому что по моему мнению такой код не должен проходить ревью.

> Каждый раз ее таскать за собой? Зачем вообще вся эта возня с компонентами, если такая логика не инкапсулируется?

Ну в реакте же вы будете это все таскать за собой? Да и в любой другой библиотеке. Какой-либо функционал, которого нет в библиотеке, вы реализуете сами и таскаете за собой. Например, если надо будет наоборот оборачивать все компоненты во врапперы, то вы что сделаете?

> И на каждом компоненте ее вызывать вместе с обычными наследованием, чтобы унаследовать еще какой-то кусок?

И в чем проблема?

> И в каком месте я это делаю в реакте?

Вы пишете в реакте обычные функции, которые реализуют функционал, которого в реакте нет. Почему вы не можете поступить так же в ангуляре?

> Я ожидаю от инструмента корректной работы со стандартными языковыми конструкциями, такими как, о боги, обычное наследование, а не подмены их своими кривоработающими велосипедами.

Он и работает корректно и ожидаемо, а ваши «хотелки» состоят в том, чтобы «было как в реакте». Это уже вопрос религиозных убеждений и обсуждать его я смысла не вижу. Вы привели выше конкретную и объективную претензию — отсутствие декларативности. И, действительно, всякие вьюрефы ей не отличаются. Я выше привел пример, как это делается без вьюрефов, с оверхедом не выше, чем в реакте. Вас это решение по уровню декларативности устраивает?
> И что, он теперь не функция? Более того, компонент со стейтом (даже класс, представьте) — это тоже функция от инпутов, но с сайд-эффектом в виде стейта.

Нет, не функция. Компоненты реакта не являются чистыми функциями, они обладают состоянием (как «внешним», то есть данные используемые при рендеринге компоненты, так и «внутренним» — состояние компоненты, изменяющееся при помощи апи-хуков и по ходу lyfecycle), которое, кстати, не является иммутабельным. А «ф-я от инпутов» — это render.

> Покажите, как вы это через ng-content без лишних оберток сделаете.

Зачем через ng-content? Это же не HOC, сделаю через наследование:
@Component({
    selector: "my-button",
    template: `<button (click)="clicked.emit()">{{ name }}</button>`,
})
export class MyButtonComponent {
    @Input() name: string;
    @Output() clicked = new EventEmitter;
}

@Component({
    selector: "my-button-with-icon",
    template: `<span>{{ icon }}</span><my-button (clicked)="clicked.emit()" [name]="name"></my-button>`,
})
export class MyButtonWithIconComponent extends MyButtonComponent {
    @Input() icon: string;
}

@Component({
    selector: "test-button",
    template: `<my-button-with-icon [name]="'name'" [icon]="'icon'" (clicked)="click()"></my-button-with-icon>`,
})
export class TestButtonComponent {
    public click() {
        console.log("Clicked!");
    }
}


Но если уж хочется через ng-content, то можно так:

@Component({
    selector: "my-button",
    template: `<button (click)="clicked.emit()">{{ name }}</button>`,
})
export class MyButtonComponent {
    @Input() name: string;
    @Output() clicked = new EventEmitter;
}

@Component({
    selector: "with-icon",
    template: `<span>{{ icon }}</span><ng-content></ng-content>`,
})
export class WithIconComponent {
    @Input() icon: string;
}

@Component({
    selector: "test-button",
    template: `<with-icon [icon]="'icon'"><my-button [name]="'name'" (clicked)="click()"></my-button><with-icon>`,
})
export class TestButtonComponent {
    public click() {
        console.log("Clicked!");
    }
}


В обоих случаях все вполне себе декларативно, нет?

> без лишних оберток

Какое-то надуманное требование. Но если хотите без оберток — можете сделать себе структурную директиву, которая будет делать unwrap вашего компонента, не вижу здесь какой-либо проблемы

> Вот он, воистину, angular-way! Вместо обычного class extend мне нужно пилить кастомный декоратор? Класс.

Декоратор — это обычная функция. В чем проблема написать обычную функцию на 10 строк для реализации своих хотелок? Почему в реакте вы так делаете и не бухтите, а в ангуляре — нельзя?
> Ну тогда ткните меня носом в место, где написано, что это low-level и что не используется для динамического создания компонентов.

Для динамического создания компонентов и используется. HOC тут при чем? Слово «Dynamic» я там вижу, слов «Higher-order» — нет. Это вам не говорит ни о чем?

> У компонента прекрасно может и не быть состояния.

Может и не быть, но в общем случае — оно есть.

> Вы что, правда не видите разницы?

Ну так вы продолжаете штаны через голову натягивать.

@Component({
    selector: "foo",
    template: `<div><ng-content></ng-content></div>`,
})
export class FooComponent {
    public data = 123;
}

// <foo #scope><my-component [someField]="scope.data"></foo>


Именно так подобного рода задачи решаются в ангуляре. Естественно, это несколько другой способ, у него по сравнению с реактовскими HOC есть как недостатки (более вербозен), так и достоинства (выше гибкость).

А всякого роды ref'ы с фабриками — это либо инструмент для построения сложных УИ по динамических конфигурациям, либо АПИ для structural directives.

> Простите, но на аргумент как-то тоже не тянет. Что за поблажка, раз 3 строчки — значит можно копипастить?

Совсем несложно написать свой вытягивающий метаданные из суперкласса декоратор (это же обычная функция), если вам это прямо надо. Будете вместо Component(...) писать @DerivedFrom(BaseComponent, {… если надо что-то перегрузить..}). То есть это решаемая проблема, и решаемая без каких-то особых затрат.
> Да что вы говорите

Именно то, что написано по указанной ссылке. Вы же ее прочли?

> Да что вы говорите

Не надо путать HOF и HOC. С точки зрения домена компонент не является ф-ей (у него, как минимум, есть еще внутреннее состояние и метаданные). При этом HOC — как раз обычная функция. Название «Higher-order component» удобно, но по факту не является корректным.

> И каким же образом вас ng-content спасет от лишней обертки? Даже если у вас весь темплейт это <ng-content><ng-content/>?

От какой обертки?

> Ну так я и пишу, нужно руками распихать все input/outputs в этот референс. Где тут декларативность?

Здесь есть несколько моментов:
1. Упомянутые выше HOF вы как вызываете? Точно так же распихивая аргументы руками, менее декларативными они от этого не становятся, правда?
2. За показанный выше проброс аргументов через spread надо вырывать руки.
3. Он возможен только в том случае, когда у вас аргументы чисто случайно совпадают — то есть, практически никогда.

> Через директиву вы не подмешаете стили.

Потому что стили — это не поведение, все верно.

> Через наследование вы не наследуете конфигурацию декоратора — придется копипастить.

Во-первых, конфигурация компонента — это три строчки, так что если бы копипаста и была, то это не помешало бы совершенно никак. Но ведь ее на самом деле и нет, вот в чем штука. Что именно вы копипастите? Стиль? Так вы его переопределили. Селектор? Он тоже другой. Только темплейт остается, да и тот не всегда.
Вы штаны через голову надеваете. ComponentFactoryResolver — низкоуровневое апи, что-то вроде рефлексии, для этих вещей оно не предназначено. Для аналога HOC (а это анти-паттерн, само по себе, и в Реакте используется только из-за бедности) есть ng-content (бывший трансклюд), доступ к текущему контексту у него есть по дефолту, а внутренний скоп компоненты инжектится через template reference variable. Это в том случае, если требуются «полноценные» HOC, для простого подмешивания поведения используются директивы или наследование (в зависимости от того, что и как надо подмешать).
12 ...
376

Information

Rating
Does not participate
Registered
Activity