> Сохранив при этом компонуемость в том виде, в котором мне нужно.
Ну как же вы сохраните? Вид и модель будут отдельно? Будут.
> Я не вижу ни одной причины гоняться за мнимым отделением шаблона от его компонента
А вы в реакте всю логику суете прям в компонент, таким вот невнятным ворохом? Ну тогда ясно все.
> Вопрос дизайна и подхода — текущий не дает мне нужной гибкости, которую дает реакт.
Как не дает, если гибкость решения на ангуляре наоборот _выше_? Все, что можно на реакте — можно легко повторить на ангуляре. Но вот если я начну просить ангуляровские вещи повторить на реакте — у вас это просто вообще не выйдет, тут сработает аналог правила Гринспена :)
> как простейшие в реакте вещи сделать с огородом костылей в 20 раз сложнее на ангуляре
Ну у вас проблема в том, что вы не понимаете архитектуры ангуляра и называете «костылями» пару строчек вполне идеоматического кода. Вы пытаетесь задаунгрейдить ангуляр до примитивного уровня реакта, где просто ничего нет. Это знаете, как сравнивать какой-нибудь ЯВУ с ассемблером. Приходит человек и говорит: «а вот я хочу параметр через стек передать для вызова подпрограммы. В ассемблере пишу две строчки и все работает — push/pop, а как у вас, в java/c#/javascript/etc? Ой какой ужас в 20 раз сложнее». Примерно так для меня ваши тезисы выглядят, если честно.
> ут идеально бы подошел интерфейс, но инжектор не умеет инжектить компоненты по интерфейсу.
Вообще умеет. Брать токен по типу — это лишь стандартное поведение, можно в аргументах в конструкторе сделать (@Inject(token) host: InterfaceComponent) и в хост заинжектится нужный токен, полностью будет как-то: ( Host() Inject(token) host: InterfaceComponent) (@Host() ограничивает инжектор, с-но, хостом), ну и в самой хост-компоненте надо зарегистрировать провайдер для соответствующего токена.
> HostListener, как и HostBinding, работает только с нативными ивентами на дом-ноде хоста.
Нет, он со всеми работает, я специально проверил.
> Да, вот только мне явно нужно знать класс компонента, к которому я прицепляюсь.
Так вы уже определитесь — вам loaded не нужен (и тогда вы точно знаете класс) или нужен (тогда не знаете). Если класс неизвестен, то делается интерфейс, который компоненты, к которым можно подмешивать нужное поведение, реализуют, и хост инжектится потом по кастомному токену
raveclassic и, собственно, вы же можете поступить как в реакте — то есть написать ф-ю, которая принимает один класс (модель), и возвращает новый — с измененным поведением. Вам только надо будет явно связать эту модель со старым видом, и все:
const template = `<div><button>{{ name }}</button></div>`;
@Component({
selector: "my-button",
template: template,
})
export class MyButtonComponent {
@Input() name = "";
}
export function loaded(component: any) {
return class extends component {
name = "loaded";
};
}
@Component({
selector: "loaded-button",
template: template,
})
export class LoadedButtonComponent extends loaded(MyButtonComponent) {};
> Идеологически на уровне редьюсера стейт с одним и тем же промисом (даже ссылка та же) но в разных состояних — это 3 разных стейта, так как по сути описывают 3 разных состояния: pending, success, fail. Это же разные состояния? Разные.
Это состояние промиса. Зачем его тащить в стейт? ПРусть будет локлаьным для промиса.
> А тут бац, сессия сдохла — как это в редьюсере похендлить?
А как вы это хендлите вне редьюсера?
> Как вы синхронно отмотаете список экшенов, когда среди них есть асинхронные?
Среди них нет асинхронных. Любой экшн — это просто тип с пейлоадом.
> А там какая-то асинхронщина, которая другие экшены выбрасывает. А в оплоге они уже есть, упс.
Вот именно. Это проблема, когда у нас произвольные сайд-эффекты, но когда эффекты ограничены (например — исключительно спавном, возможно асинхронным, других экшенов), то они не оказывают влияния ни на стор, ни на ход рендера, по-этому мы можем просто мокнуть ф-ю, которая внутри редьюсера вызывает эффект, в x => {return;}, которая ничего не делает.
> Собственно undo/redo так и делается. Там не экшены применяются/отменяются, а просто заменяется весь стейт.
В этом случае редьюсеры не вызываются и вообще никаких проблем нет. Мотай себе стейт куда захочешь и как захочешь.
«Чистую» часть редьюсеров вы можете тестировать так же просто. а «Грязная»… ну она и в оригинальном редаксе была грязной, просто находилась не в редьюсерах.
> Нет, в зависимости от состояния этого промиса, результаты будут разные.
С чего бы это? Мы же не делаем await промиса в редьюсере, редьюсер только создает промис, но не ожидает его завершения. Потом в then промиса диспатчится какой-то экшон и уходит в стор. В итоге у нас в стор в обоих случаях приходит вполне детерменированно два одинаковых экшона в одном и том же порядке.
> Он не должен что-то там спавнить по ходу, так как сразу обрастет сайд-эффектом.
Этот сайдэффект все равно есть. И от того что вы его отодвинули ничего не меняется — ну это просто заметание под ковер.
> И я не очень понимаю, почему выполнение эффекта вне редьюсера вызывает столько негодования.
Потому что это неудобно. Вот и все. И при этом ничего не дает.
> Держа редьюсеры чистыми, вы на халяву получаете простоту отладки, простоту тестирования, тайм-тревелинг, undo/redo и прочее-прочее.
В описываемом мной случае все точно так же — у нас линейная последовательность экшенов, которую можно отматывать и так далее.
Надо просто во все инпуты, где пробрасываются именно данные (а не константы/конфиги) делать по дефолту обсерваблами (и, с-но, асинк в темплейте). Это даже не то что для таких вот случаев, а в принципе архитектура ангуляра заточена больше под такой flow, он в целом будет удобнее (хотя поначалу и непривычно).
Вполне детерменирован — он же вернет в точности тот же результат. Просто по пути заспавнит экшон, который придет потом в стор. В точности то же самое и в приведенном выше решении — просто экшен заспавнится несколько раньше. Единственное, что нам нужно — чтобы сама последовательность экшенов не нарушалась — ведь состояние стора больше ни от чего не зависит! Если последовательность обработки экшенов неизменна — то и состояние стора на каждом шаге будет тем же. А когда и как запускаются промисы — вобщем-то не важно, это деталь реализации, которая не влияет на результат.
Ну это странное мнение, учитывая что attribute directives предназначены _именно_ для решения таких проблем. То есть вот он инструмент специально для этого заточенный.
> UPD: Кстати, а HostBinding поддерживает async pipe?
В каком смысле? Пайпы же находятся в темплейте. Если вы хотите сделать так, чтобы какоето проперти, которое использовалось без асинка, начало использоваться как бы с асинком — то насколько я знаю, так нельзя, надо делать subscribe и менять обычное значение. Но если оно и так уже было с асинком — то вы можете засунуть туда observable.
Я не понял. И так, у вас есть компонент, у компонента какие-то пропсы. Вы хотите сделать в точности такой же компонент с таким же видом, но чтобы в нем не было пропсов, а он сам подгружал данные (с сервера, редаксом, еще как -либо — не важно)? Все так? Тогда делаете attribute directive и выставляете инпуты хоста через @HostBinding, нет?
еще я мог в декларации провайдера напутать, я ее не помню, надо в доках смотреть
Ну а теперь перепишите это к нормальному виду, для полноценной задачи, чтобы бизнес-логика была вынесена в отдельный класс хотя бы.
> Если мне понадобиться вынести логику в «модель», я вынесу и буду принимать ее через props.
Ну так продемонстрируйте. На однострочниках-то все всегда хорошо :)
> А если еще дальше — я поставлю inversifyjs и буду инжектить ее прямо в компонент/контейнер. Все.
Ну так вы не стесняйтесь, продемонстрируйте то, о чем сейчас так лихо рассказали. Я же не так просто правило Гринспена вспомнил :)
> Ну давайте, жгите!
Давайте с чего-нибудь простого начнем. Сделайте мне аналог компоненты с селектором-атрибутом.
както так
Ну как же вы сохраните? Вид и модель будут отдельно? Будут.
> Я не вижу ни одной причины гоняться за мнимым отделением шаблона от его компонента
А вы в реакте всю логику суете прям в компонент, таким вот невнятным ворохом? Ну тогда ясно все.
> Вопрос дизайна и подхода — текущий не дает мне нужной гибкости, которую дает реакт.
Как не дает, если гибкость решения на ангуляре наоборот _выше_? Все, что можно на реакте — можно легко повторить на ангуляре. Но вот если я начну просить ангуляровские вещи повторить на реакте — у вас это просто вообще не выйдет, тут сработает аналог правила Гринспена :)
> как простейшие в реакте вещи сделать с огородом костылей в 20 раз сложнее на ангуляре
Ну у вас проблема в том, что вы не понимаете архитектуры ангуляра и называете «костылями» пару строчек вполне идеоматического кода. Вы пытаетесь задаунгрейдить ангуляр до примитивного уровня реакта, где просто ничего нет. Это знаете, как сравнивать какой-нибудь ЯВУ с ассемблером. Приходит человек и говорит: «а вот я хочу параметр через стек передать для вызова подпрограммы. В ассемблере пишу две строчки и все работает — push/pop, а как у вас, в java/c#/javascript/etc? Ой какой ужас в 20 раз сложнее». Примерно так для меня ваши тезисы выглядят, если честно.
Вообще умеет. Брать токен по типу — это лишь стандартное поведение, можно в аргументах в конструкторе сделать (@Inject(token) host: InterfaceComponent) и в хост заинжектится нужный токен, полностью будет как-то: ( Host() Inject(token) host: InterfaceComponent) (@Host() ограничивает инжектор, с-но, хостом), ну и в самой хост-компоненте надо зарегистрировать провайдер для соответствующего токена.
Нет, он со всеми работает, я специально проверил.
> Да, вот только мне явно нужно знать класс компонента, к которому я прицепляюсь.
Так вы уже определитесь — вам loaded не нужен (и тогда вы точно знаете класс) или нужен (тогда не знаете). Если класс неизвестен, то делается интерфейс, который компоненты, к которым можно подмешивать нужное поведение, реализуют, и хост инжектится потом по кастомному токену
Чтобы можно было подмешивать поведение к разным компонентам. А если этого не надо, то вообще не понятно, в чем была исходная проблема.
> Плюс у меня есть смутные подозрения, что, выносят темплейт из класса, мы теряем всяческую помощь IDE внутри этого темплейта.
В тайпскрипте уже сделали language-service, так что это не проблема теперь.
> Зачем должна, кому должна,
Человеческой архитектуре. В реакте-то вы все равно к той же схеме придете, так какая разница.
С декларативными эффектами она не грязная :)
Но оверхед от достижения этой декларативности кажется значительно превышающим какой-то один мок.
Это состояние промиса. Зачем его тащить в стейт? ПРусть будет локлаьным для промиса.
> А тут бац, сессия сдохла — как это в редьюсере похендлить?
А как вы это хендлите вне редьюсера?
> Как вы синхронно отмотаете список экшенов, когда среди них есть асинхронные?
Среди них нет асинхронных. Любой экшн — это просто тип с пейлоадом.
> А там какая-то асинхронщина, которая другие экшены выбрасывает. А в оплоге они уже есть, упс.
Вот именно. Это проблема, когда у нас произвольные сайд-эффекты, но когда эффекты ограничены (например — исключительно спавном, возможно асинхронным, других экшенов), то они не оказывают влияния ни на стор, ни на ход рендера, по-этому мы можем просто мокнуть ф-ю, которая внутри редьюсера вызывает эффект, в x => {return;}, которая ничего не делает.
> Собственно undo/redo так и делается. Там не экшены применяются/отменяются, а просто заменяется весь стейт.
В этом случае редьюсеры не вызываются и вообще никаких проблем нет. Мотай себе стейт куда захочешь и как захочешь.
С чего бы это? Мы же не делаем await промиса в редьюсере, редьюсер только создает промис, но не ожидает его завершения. Потом в then промиса диспатчится какой-то экшон и уходит в стор. В итоге у нас в стор в обоих случаях приходит вполне детерменированно два одинаковых экшона в одном и том же порядке.
> Он не должен что-то там спавнить по ходу, так как сразу обрастет сайд-эффектом.
Этот сайдэффект все равно есть. И от того что вы его отодвинули ничего не меняется — ну это просто заметание под ковер.
> И я не очень понимаю, почему выполнение эффекта вне редьюсера вызывает столько негодования.
Потому что это неудобно. Вот и все. И при этом ничего не дает.
> Держа редьюсеры чистыми, вы на халяву получаете простоту отладки, простоту тестирования, тайм-тревелинг, undo/redo и прочее-прочее.
В описываемом мной случае все точно так же — у нас линейная последовательность экшенов, которую можно отматывать и так далее.
Вполне детерменирован — он же вернет в точности тот же результат. Просто по пути заспавнит экшон, который придет потом в стор. В точности то же самое и в приведенном выше решении — просто экшен заспавнится несколько раньше. Единственное, что нам нужно — чтобы сама последовательность экшенов не нарушалась — ведь состояние стора больше ни от чего не зависит! Если последовательность обработки экшенов неизменна — то и состояние стора на каждом шаге будет тем же. А когда и как запускаются промисы — вобщем-то не важно, это деталь реализации, которая не влияет на результат.
Ну это странное мнение, учитывая что attribute directives предназначены _именно_ для решения таких проблем. То есть вот он инструмент специально для этого заточенный.
> UPD: Кстати, а HostBinding поддерживает async pipe?
В каком смысле? Пайпы же находятся в темплейте. Если вы хотите сделать так, чтобы какоето проперти, которое использовалось без асинка, начало использоваться как бы с асинком — то насколько я знаю, так нельзя, надо делать subscribe и менять обычное значение. Но если оно и так уже было с асинком — то вы можете засунуть туда observable.