И кто помешает мне вызывать navigate(route, anyObject) с anyObject, неподходящим под сигнатуру роута route? Какой толк от типа, который ничего не фиксирует?
> Зачем бить «туда» и «обратно» на два разных куска, если это всё можно задать 1 раз декларативно?
> В JSX я вижу не ноду, а преобразование — список айтемов преобразуется в список нод, мы всегда отталкиваемся от данных.
Так именно это проблемой и является. В шаблонизаторе вы видите результат преобразования, в JSX — преобразование. Чтобы по преобразованию получить результат — надо его выполнить в уме.
> для for есть единственный вариант — map
для if — && и тернарник, не так уже и много
Ага, конечно. Только вот есть те же «а-ля шаблонизатор», есть сдабривание iife, есть просто подергивание каких-то методов (которые хрен его знает, что могут возвращать, пока не посмотришь, а потому факт наличия цикла вы сразу и не сможете определить).
> В ангуляре-то пара, а кастомных в природе сколько?
Во втором структурные еще специально звездочкой принято помечать. Так что уж не пропустишь.
> Но вот только в ПХП был серверный код бизнес-логики вперемешку с HTML.
Ну так в SPA у вас тот же код, который раньше был серверным, теперь на клиенте.
> Но их никто не использует. Потому что настоящая мощь Реакта — в том факте, что компоненты — это обычные JS объекты. Я не устаю писать это в каждом комментарии в сраче о JSX.
Так их никто не использует, потому что реакт плохо с этим работает. Он заточен под пехепешную модель, т.к. создавался для портирования php-кода на js.
> Шаблон Ангуляра — это, конечно, похоже на ХТМЛ (особенно, если ты видел пример из getting started и не видел реальный production код). Но это все-равно строка.
Во втором ангуляре шаблоны компилируются в js-объект, точно так же, как jsx.
> А вот как взять потомков одного типа, и склонировать их для каждого элемента массива и отрендерить в отдельное место?
Легко догадаться, что так делать не надо. Надо описать модель данных, в которой будет «взять, склонировать» и что там еще надо, а потом по этим данным, используя примитивные операции, нагенерить вьюху. В итоге в одном месте вы работаете с чистыми данными (ничего не зная о дом), а в другом — примитивным образом их визуализируете. JSX, как видно, стимулирует мешать все в одну невнятную кучу, да еще и предлагает этот баг в виде фичи.
> 1 и 2 — одно и то же, ибо существование того или иного узла зависит от какого-то состояния.
Нет, не то же. Именно в том и соль, что во втором случае менять локальное состояние руками вы не должны, следует отреагировать на евент.
Естественно, руками можно все стейты смержить в один. Но именно в этом и были мои хотелки — я хочу, чтобы это делал фреймворк, за меня. А я смогу обрабатывать любые варианты юниморфно.
И, да, можно написать указанный код на чистом js? Я не знаю, как парсить ваши ребусы. И реализацию killed для первого случая еще хотелось бы увидеть.
> В «разметке» останется JS. Чистый, обычный и валидный
Который надо в уме исполнить, чтобы понять, чего этот JS нагенерит. А в случае с ng-repeat я сразу вижу готовую ноду, потом надо только отметить, что: «ага, эту ноду размножить, раз там ng-repeat». К слову, таких директив в ангуляре всего-то пара штук (то есть легко запомнить), а сколько есть разных вариантов записи для аналогов for/if в JSX? Да десятки.
Вы невнимательно прочитали мой пост. Я же специально указал — проблема не в кривом синтаксисе _самом по себе_. Он не очень, но к любому синтаксису привыкаешь. Проблема именно в наличии «а как вам вот так» — в том, что одно и то же можно сделать по-разному. Когда мы работаем с шаблонизатором, то мы видим перед собой уже практически готовую верстку, в которой глаз сразу ухватится за некоторые выделенные токены (вроде ng-repeat), то есть это html + добавка. В случае с JSX мы имеем дело с js + добавка, что на порядок сложнее для разбора. Чтобы понять, что сгенерирует js-код — ну, надо разобрать этот код, понять, что он нагенерит. В случае шаблонизатора — вам и не надо ничего разбирать, вы уже довольно-таки точно видите, что получится в итоге. Шаблонизаторы именно потому хороши, что они используют возможности html, а никто лучше html языка для описания dom не придумал. JS ему сильно в этом проигрывает, именно в силу своей универсальности.
Там много непонятных картинок и мало кода. Хотелось бы увидеть следующие примеры:
1. Пользователь кликает по кнопке, некоторая существующая дом-нода удаляется (пусть сама кнопка и удаляется?)
2. Меняется локальный стейт (значение isHidden), дом-нода удаляется
3. Меняется глобальный стейт (значение isHidden), дом-нода удаляется
4. Срабатывает lyfecycle хук (если у ваших компонент они есть) — дом-нода удаляется
> Или хоть что-либо отличное от каши any[] в [routerLink]
Роут нельзя типизировать, потому что это по определению — просто строка. К слову, все ваши предложения с "/category-{id}{aux:/item-{id}}" сразу блокируют в роутерлинке что-либо кроме any[].
> К сожалению, не панацея. Я хочу проверку ссылки в момент ее генерации (о проверке в compile-time я уже не говорю).
Кто мешает?
> Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"),
А чем вас, собственно, не устраивает /category;id={id}? тем, что ";" вместо "-"?
> Но есть и обратная сторона: здесь смешали html и управляющие конструкции.
В варианте на JSX смешали не просто html и управляющие инструкции, а html и большее подмножество JS.
> Если на навесить еще class, ng-click, то потом будет сложно беглым взглядом найти ng-repeat.
ng-repeat как раз будет отлично виден всегда — именно потому, что это одна из немногих управляющих конструкций. Она всегда выглядит одинаково и используется одинаково. В случае же jsx глазу вообще не за что зацепиться — вам надо распарсить полностью произвольный js код (что на порядок сложнее, чем вычленить один токен) и понять его семантику. Понимаете, в чем разница? Это очевидное преимущество специализированных решений над универсальными. JS — универсальный язык, и он откровенно плох в генерации представления для разметки, потому как никогда для этого предназначен не был, JSX улучшает картину, но несущественно. Шаблонизаторы — лучше, потому что они специально заточены для построения представлений конкретного вида. Именно по-этому даже PHP выигрывает у JSX по удобству описания разметки. Он для этого предназначен, он для этого был спроектирован. JSX — нет.
> Однако хорошо оформленный JSX удобнее, чем пара JS+шаблон.
Можно увидеть этот самый «хорошо оформленный JSX»? Чтобы там не было кучи ненужных мелких компонент (сильно затрудняющих восприятие разметки в целом) или чего-нибудь вот такого:
и проблема здесь не в самом факте перегруженности синтаксиса, к синтаксису можно было бы привыкнуть, если бы не одно «но»: в случае с шаблонизатором обычно есть один ясный и понятный способ решить задачу, которую решает данный кусок кода. Вы возьмете 10 программистов и вам 10 напишут одинаково. В случае с JSX — каждый, блин, напишет как-то по-своему.
> Хотя бы потому, что в JSX вы не можете открыть тег и не закрыть его. У JSX строгий синтаксис, который не позволит вам наделать нелепых ошибок в разметке.
Проблема с генережкой html-разметки в PHP никогда и не имела ничего общего с незакрытыми тегами и нелепыми ошибками, проблема была в том, что код неизбежно превращается в невнятную помесь какашек.
По-этому реакция на JSX у подавляющего большинства людей, имеющих серьезный опыт работы с PHP — вполне ожидаема и закономерна. Особенно, когда они видят _реальный_ JSX-код (из реального приложения, а не из примеров) и понимают, что, да, первое впечатление не обмануло — это PHP в худших его проявлениях, как выше сказали — привет из 90-х, все ровно так, будто одел старый разлезшийся свитер.
То есть, люди набили шишки, настрадались, прошли этот этап — а теперь им предлагают есть те же какашки, что были в прошлом. Естественно, никто повторять свои страдания не захочет, пусть страдают те, кто еще не настрадался :)
> Еще иногда на динамике быстрее и легче писать мелкие скрипты до ста строк.
Это вообще верно было пока нормально не проработали системы типов для динамических языков. Сейчас на том же TS 99% идиоматического js-кода прекрасно типизируется безо всяких проблем (разве что проблемы с прототипным наследованием, потому что его никто не изучал особо), а оверхед по объявлению типов — по факту нулевой.
Тогда как решается проблема работы «по-разному» с разными «кусками» стейта? Как минимум, должна быть возможность одинаково работать с эвентами интерфейса и внутренним стейтом компонента. То есть, они должны быть представлены объектами, реализующими один и тот же интерфейс. Что это у вас за объект и что за интерфейс?
> Явно не за полчаса + странный аргумент для «batteries included» фреймворка.
«batteries included» никогда не означало наличие редко нужного функционала, вопрос реализации которого — сотня строк кода.
> обработка валидности входных параметров в контроллере же (как предполагается самим фреймворком) — явное смешивание полномочий.
Это правильно, валидность надо проверять в роутере. В ангуляре специально для этого есть canActivate гварды. При этом проверять можно не только формат синтаксиса, а выполнение любых условий. Например, роут foo/:id при несуществующем в базе айдишнике столь же невалиден, сколь и роут с неправильным синтаксисом.
> В самом общем случае урл выглядит как "...[var1:format]...[var2:format]...[var3:format]..." Зачем было искусственно это ограничивать — я так и не понял
Ваш «общий случай» не учитывает синтаксиса аргументов и именованных аутлетов (как раз тот функционал, который «на коленке» не напишешь), а потому просто не работает.
> Но примешивает её сама сущность (функция, класс, модуль), а не тот, кто эту сущность использует.
Вы слишком большое внимание уделяете синтаксису (то, что строчка с миксином внутри определения класса), смотрите на семантику (да, к слову, в большинстве вариантов реализации миксин применяется на готовый класс явно, то есть и синтаксически «снаружи»). В вашем случае — миксин не внутри класса, к которому вы его применили. Он внутри класса-результата. А класс, к которому применен миксин — это class _Anonymous { string name; }
Это зависит уже конкретно от языка. Важно-то, что в любом случае везде примеси — внешние сущности. В вашем же примере из вики — примесь comparable ничего не знает о классе, к которому применяется, и действует на него «снаружи».
Если класс реализует нужные для примеси интерфейсы — вы всегда можете совершенно внешним образом этих примесей туда понасовать.
Именно этого и хочу. В вашем же случае работы с эвентами и внутренним стейтом происходит неединообразно.
> Зачем?
Чтобы работать с ними одинаково.
> Из того view.tree генерируется примерно следующий ts-класс:
Ну вот вы руками мержите стейт — вешаете колбек на клик. Именно этого я и хотел бы избежать. Где там, кстати, сама логика сокрытия кнопки?
И кто помешает мне вызывать navigate(route, anyObject) с anyObject, неподходящим под сигнатуру роута route? Какой толк от типа, который ничего не фиксирует?
> Зачем бить «туда» и «обратно» на два разных куска, если это всё можно задать 1 раз декларативно?
Что бить?
> А где должна быть эта функция?
Там, где вы описываете роут, очевидно.
Так именно это проблемой и является. В шаблонизаторе вы видите результат преобразования, в JSX — преобразование. Чтобы по преобразованию получить результат — надо его выполнить в уме.
> для for есть единственный вариант — map
для if — && и тернарник, не так уже и много
Ага, конечно. Только вот есть те же «а-ля шаблонизатор», есть сдабривание iife, есть просто подергивание каких-то методов (которые хрен его знает, что могут возвращать, пока не посмотришь, а потому факт наличия цикла вы сразу и не сможете определить).
> В ангуляре-то пара, а кастомных в природе сколько?
Во втором структурные еще специально звездочкой принято помечать. Так что уж не пропустишь.
Ну так в SPA у вас тот же код, который раньше был серверным, теперь на клиенте.
> Но их никто не использует. Потому что настоящая мощь Реакта — в том факте, что компоненты — это обычные JS объекты. Я не устаю писать это в каждом комментарии в сраче о JSX.
Так их никто не использует, потому что реакт плохо с этим работает. Он заточен под пехепешную модель, т.к. создавался для портирования php-кода на js.
> Шаблон Ангуляра — это, конечно, похоже на ХТМЛ (особенно, если ты видел пример из getting started и не видел реальный production код). Но это все-равно строка.
Во втором ангуляре шаблоны компилируются в js-объект, точно так же, как jsx.
> А вот как взять потомков одного типа, и склонировать их для каждого элемента массива и отрендерить в отдельное место?
Легко догадаться, что так делать не надо. Надо описать модель данных, в которой будет «взять, склонировать» и что там еще надо, а потом по этим данным, используя примитивные операции, нагенерить вьюху. В итоге в одном месте вы работаете с чистыми данными (ничего не зная о дом), а в другом — примитивным образом их визуализируете. JSX, как видно, стимулирует мешать все в одну невнятную кучу, да еще и предлагает этот баг в виде фичи.
Нет, не то же. Именно в том и соль, что во втором случае менять локальное состояние руками вы не должны, следует отреагировать на евент.
Естественно, руками можно все стейты смержить в один. Но именно в этом и были мои хотелки — я хочу, чтобы это делал фреймворк, за меня. А я смогу обрабатывать любые варианты юниморфно.
И, да, можно написать указанный код на чистом js? Я не знаю, как парсить ваши ребусы. И реализацию killed для первого случая еще хотелось бы увидеть.
И какой тип аргумента navigate у вашего примера? И как его выразить в рамках системы типов ТС?
> Вообще не понял вопроса, если честно.
Я говорю, кто не дает вам валидировать роуты в момент создания? У вас есть ф-я, которая генерит роуты, в чем проблема проверять роут в ней?
Который надо в уме исполнить, чтобы понять, чего этот JS нагенерит. А в случае с ng-repeat я сразу вижу готовую ноду, потом надо только отметить, что: «ага, эту ноду размножить, раз там ng-repeat». К слову, таких директив в ангуляре всего-то пара штук (то есть легко запомнить), а сколько есть разных вариантов записи для аналогов for/if в JSX? Да десятки.
Вы невнимательно прочитали мой пост. Я же специально указал — проблема не в кривом синтаксисе _самом по себе_. Он не очень, но к любому синтаксису привыкаешь. Проблема именно в наличии «а как вам вот так» — в том, что одно и то же можно сделать по-разному. Когда мы работаем с шаблонизатором, то мы видим перед собой уже практически готовую верстку, в которой глаз сразу ухватится за некоторые выделенные токены (вроде ng-repeat), то есть это html + добавка. В случае с JSX мы имеем дело с js + добавка, что на порядок сложнее для разбора. Чтобы понять, что сгенерирует js-код — ну, надо разобрать этот код, понять, что он нагенерит. В случае шаблонизатора — вам и не надо ничего разбирать, вы уже довольно-таки точно видите, что получится в итоге. Шаблонизаторы именно потому хороши, что они используют возможности html, а никто лучше html языка для описания dom не придумал. JS ему сильно в этом проигрывает, именно в силу своей универсальности.
1. Пользователь кликает по кнопке, некоторая существующая дом-нода удаляется (пусть сама кнопка и удаляется?)
2. Меняется локальный стейт (значение isHidden), дом-нода удаляется
3. Меняется глобальный стейт (значение isHidden), дом-нода удаляется
4. Срабатывает lyfecycle хук (если у ваших компонент они есть) — дом-нода удаляется
Роут нельзя типизировать, потому что это по определению — просто строка. К слову, все ваши предложения с "/category-{id}{aux:/item-{id}}" сразу блокируют в роутерлинке что-либо кроме any[].
> К сожалению, не панацея. Я хочу проверку ссылки в момент ее генерации (о проверке в compile-time я уже не говорю).
Кто мешает?
> Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"),
А чем вас, собственно, не устраивает /category;id={id}? тем, что ";" вместо "-"?
В варианте на JSX смешали не просто html и управляющие инструкции, а html и большее подмножество JS.
> Если на навесить еще class, ng-click, то потом будет сложно беглым взглядом найти ng-repeat.
ng-repeat как раз будет отлично виден всегда — именно потому, что это одна из немногих управляющих конструкций. Она всегда выглядит одинаково и используется одинаково. В случае же jsx глазу вообще не за что зацепиться — вам надо распарсить полностью произвольный js код (что на порядок сложнее, чем вычленить один токен) и понять его семантику. Понимаете, в чем разница? Это очевидное преимущество специализированных решений над универсальными. JS — универсальный язык, и он откровенно плох в генерации представления для разметки, потому как никогда для этого предназначен не был, JSX улучшает картину, но несущественно. Шаблонизаторы — лучше, потому что они специально заточены для построения представлений конкретного вида. Именно по-этому даже PHP выигрывает у JSX по удобству описания разметки. Он для этого предназначен, он для этого был спроектирован. JSX — нет.
Можно увидеть этот самый «хорошо оформленный JSX»? Чтобы там не было кучи ненужных мелких компонент (сильно затрудняющих восприятие разметки в целом) или чего-нибудь вот такого:
и проблема здесь не в самом факте перегруженности синтаксиса, к синтаксису можно было бы привыкнуть, если бы не одно «но»: в случае с шаблонизатором обычно есть один ясный и понятный способ решить задачу, которую решает данный кусок кода. Вы возьмете 10 программистов и вам 10 напишут одинаково. В случае с JSX — каждый, блин, напишет как-то по-своему.
Проблема с генережкой html-разметки в PHP никогда и не имела ничего общего с незакрытыми тегами и нелепыми ошибками, проблема была в том, что код неизбежно превращается в невнятную помесь какашек.
По-этому реакция на JSX у подавляющего большинства людей, имеющих серьезный опыт работы с PHP — вполне ожидаема и закономерна. Особенно, когда они видят _реальный_ JSX-код (из реального приложения, а не из примеров) и понимают, что, да, первое впечатление не обмануло — это PHP в худших его проявлениях, как выше сказали — привет из 90-х, все ровно так, будто одел старый разлезшийся свитер.
То есть, люди набили шишки, настрадались, прошли этот этап — а теперь им предлагают есть те же какашки, что были в прошлом. Естественно, никто повторять свои страдания не захочет, пусть страдают те, кто еще не настрадался :)
Это вообще верно было пока нормально не проработали системы типов для динамических языков. Сейчас на том же TS 99% идиоматического js-кода прекрасно типизируется безо всяких проблем (разве что проблемы с прототипным наследованием, потому что его никто не изучал особо), а оверхед по объявлению типов — по факту нулевой.
«batteries included» никогда не означало наличие редко нужного функционала, вопрос реализации которого — сотня строк кода.
> обработка валидности входных параметров в контроллере же (как предполагается самим фреймворком) — явное смешивание полномочий.
Это правильно, валидность надо проверять в роутере. В ангуляре специально для этого есть canActivate гварды. При этом проверять можно не только формат синтаксиса, а выполнение любых условий. Например, роут foo/:id при несуществующем в базе айдишнике столь же невалиден, сколь и роут с неправильным синтаксисом.
> В самом общем случае урл выглядит как "...[var1:format]...[var2:format]...[var3:format]..." Зачем было искусственно это ограничивать — я так и не понял
Ваш «общий случай» не учитывает синтаксиса аргументов и именованных аутлетов (как раз тот функционал, который «на коленке» не напишешь), а потому просто не работает.
Вы слишком большое внимание уделяете синтаксису (то, что строчка с миксином внутри определения класса), смотрите на семантику (да, к слову, в большинстве вариантов реализации миксин применяется на готовый класс явно, то есть и синтаксически «снаружи»). В вашем случае — миксин не внутри класса, к которому вы его применили. Он внутри класса-результата. А класс, к которому применен миксин — это class _Anonymous { string name; }
Это зависит уже конкретно от языка. Важно-то, что в любом случае везде примеси — внешние сущности. В вашем же примере из вики — примесь comparable ничего не знает о классе, к которому применяется, и действует на него «снаружи».
Если класс реализует нужные для примеси интерфейсы — вы всегда можете совершенно внешним образом этих примесей туда понасовать.
Многое говорит о разработчиках Flux.