Pull to refresh

Comments 41

И что, реально получается сделать модули независимыми друг от друга? Как быть с модулями а-ля дашборды, агрегирующими данные из многих источников? Как быть с модулями объективно связанных коллекций сущностей типа клиентов и заказов, когда нужно то конкретного клиента посмотреть со всеми его заказами, то список заказов с ФИО клиента?

Выглядит очень увлекательно. А чего демку куда-нибудь не выложили, чтобы можно было руками пощупать что получилось?

Возможно, выложу в open-source в среднесрочной перспективе. Пока нет достаточно времени для того, чтобы аккуратно все оформить. Вообще, приложенного кода достаточно, чтобы самостоятельно развернуть такую структуру, хотя придется конечно потратить время.
Модули не зависимы друг от друга. Модификация любого модуля не влияет на работу других модулей. Допускается зависимость модулей от «ядра» системы.
Это неизбежно приводит к распуханию ядра от всякой никак не связанной с ним фигни. Или вы смогли как-то это решить?
Сложно точно ответить без знания специфики вашего проекта. Расскажу как у нас. Любой подход, технология — работают в рамках каких-то ограничений. У нас большой объем разработки «учетных систем» и прочей «автоматизации бизнеса». Энтерпрайз короче. Самые часто используемые компоненты — это гриды, пагинации, деревья, формы. Т.е. инструменты манипуляции с данными. Все эти компоненты конфигурируются схемой данных, чтобы избежать неявного дублирования кода.

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

Если нужно сделать 2 примерно одинаковых модуля, но один — с перламутровыми пуговицами, используется техника copy/paste. Да, если захочется изменить оба модуля, то придется в два раза больше исправлять, но эта а) эту работу можно дать двум разработчикам, а не одному, б) если модули были чуть-чуть разными, то при модификации с большой вероятностью они разъедутся со всеми вытекающими из «хрупкого базового класса».

Чтобы ядро не «распухало» для UI нужно выбирать какие-то пакеты компонентов и ставить через npm.

А в чём проблема повторного использования графиков и прочего rich ui?

Ну я больше имел в виду ситуации, когда, есть у вас например модуль с дэшбордом и модуль с виджетом. Дэшборд настраивается пользователем, можно выбрать разные типы виджетов, лежащих, соответственно, в разных модулях (ну, если мы по фичам делим). Как избежать связывания?
А что мешает положить эту логику в App и использовать как мастер-пейдж для всего приложения? Или там гипотетические 100500 дешбордов в 27 конфигурациях?
Ну т.е. появляется некий «App», который «где-то» лежит, но если все на модулях, то модуль App ссылается на остальных. Упс.
Ну и опять же, с какой стати App должен знать о связи Dashboard -> Widget?
Это просто палка о двух концах, все хорошо делится на модули до появления первого связующего модуля, а потом начинаются пляски вокруг Core/Shared/<как_угодно>.

Edit: ну, dashboard — один из многих разделов большого App, сунуть его туда целиком нельзя.
Я думаю, это уже очень специфичный для проекта вопрос. Может быть в вашем случае монолит — более удачное решение.

Связанность между модулями — это нормально в целом. Ненормальна высокая связанность, особенно с нарушением инкапсуляции используемого модуля.

И как отличить, когда связанность высокая, а когда не очень, особенно если над проектом работает человек 50 из трех часовых поясов?)

Субъективно, конечно. Обычно понимаешь, что связь высокая когда в рамках одной задачи приходится перелопачивать кучу кода в разных модулях.

UFO just landed and posted this here
  1. Полифилы для генераторов чего-то весят, сага чего-то весит, бандл получается увесистый
  2. Не все понимают генераторы. Крутая кривая обучения
  3. Компоновка саг — не тривиально

Т.е. больше из-за ограничений практического применения. С теоретической точки зрения мне саги больше нравятся.
const Profile = default (props) => (<h2>Привет, {props.name}</h2>)

Никогда раньше такого не видел, зачем тут default?

Ошибка при форматировании. Исправил.

Про onEnter, получите и распишитесь. :)


v4 is a complete rewrite. As such, there is no singular breaking change. We have some similar-looking things (<Route path="/foo" component={Foo} />), but the behaviors are completely different. You should expect none of your existing react-router usage to work under 4.0.

As for the on* hooks, they were removed because they already exist in React as the lifecycle methods. We were reimplementing them inside the Router, but they didn't exactly behave like they should. So, why provide an inferior or conflicting API? Everything is way more React-y now, and it's way better as a result. You no longer have to mix paradigms or code for two different systems. It's just React now. It's a much lower cognitive load.

And for "plain routes", we've extracted that to a separate package: https://github.com/ReactTraining/react-router/tree/master/packages/react-router-config You can see the reasoning for this here:

The approach being taken for 4.0 is to strip out all the "batteries included" kind of features and get back to just basic routing. If you need query string parsing or async loading or Redux integration or something else very specific, then you can add that in with a library specifically for your use case. Less cruft is packed in that you don't need and you can customize things to your specific preferences and needs.
Пока четвертый роутер вообще использовать нельзя серьезно. С переходом можно легко «поправить» эту проблему. Так как все компоненты регистрируются в роутере в одном файле — routes.js, то просто оборачиваем целевой компонент в обертку с вызовом onEnter. Рефакторинга на 30 минут.
На этой неделе на хабре цикл статей инфы 3х летней давности?

В мире JS опять всё поменялось? :-)

Такой же подход применяется в Drupal CMS
При вашем подходе проектом легче управлять, есть ТЗ на модуль, есть ответственный.
Что внутри не так и важно, лишь бы работал.
Мне лично более симпатичен подход, когда в команде есть несколько спецов, которые пишут инструмент, а остальные его применяют. Но здесь требуется более тесное взаимодействие.
Это не критика, наверняка у вас все продумано. Так, рассуждения.

Есть вопрос по поводу redux: какой смысл использовать mapStateToProps? Умный контейнер прекрасно передает глупым компонентам свое состояние и каллбэки, setState вызывает цепочку рендеров. Реализация через редюсеры — это еще один уровень сложности. Зачем?
Я понимаю, когда нужно отправить команду на самый верх, чтобы она сверху вниз взбодрила кого надо, но в отношении родитель/дети redux лишний (имхо). Простое лучше сложного.
Спасибо.
Все верно, не надо складывать в стор абсолютно весь стейт приложения. Только необходимые app-wide вещи. Все остальное отлично умещается в контейнере.
Мне лично более симпатичен подход, когда в команде есть несколько спецов, которые пишут инструмент, а остальные его применяют. Но здесь требуется более тесное взаимодействие.

У нас «инструмент» — это ядро. Ядро пишут несколько человек. Остальная команда в основном использует. По примеру специалист еще не знакомый со стеком, может реализовать простой модуль не вникая в то, что под капотом. Более сложные модули требуют более высокой квалификации.

Есть вопрос по поводу redux: какой смысл использовать mapStateToProps? Умный контейнер прекрасно передает глупым компонентам свое состояние и каллбэки, setState вызывает цепочку рендеров. Реализация через редюсеры — это еще один уровень сложности. Зачем?
Я понимаю, когда нужно отправить команду на самый верх, чтобы она сверху вниз взбодрила кого надо, но в отношении родитель/дети redux лишний (имхо).

Эту часть не вполне понял :) Может привести пример?

Вообще не использую локальный стейт. Всё в сторе redux-а. Минус один уровень абстракции. Простое лучше сложного. :)


Есть такая болезнь — коннектобоязнь, описана Ильей Климовым в докладе.

Пока, скажем так, адекватного решения проблемы нет

Чудесно. Для сравнения:


  1. Открываем: http://mol.js.org/#demo=mol_app
  2. Открываем консоль и включаем эмуляцию GPRS на вкладке Network для наглядности.
  3. Вручную меняем локаль на английскую: $mol_locale.lang( 'en' )
  4. Во всех блоках, где выводились локализованные строки включился индикатор загрузки.
  5. Через какое-то время все русские тексты поменялись на английские.

И для этого не пришлось вообще ничего специально делать. Достаточно просто получить текст таким образом: $mol_locale.text( [ '$mol_app_demo' ] , 'title' )

Я почти уверен, что mol прекрасен. Больше того, может озолотить (когда-то меня приняли без экзаменов в Мамбу, как опытного спеца по велосипеду OnPHP). Но пока буду дальше жевать кактус по имени React. :)

vintage ну вот блин, я тоже смотрел на $mol в свободное время. Споткнулся о несусветную документацию из серии «ну вот я так думаю, а дальше вы сами». И пост я ваш читал о введении в ваш движок. И обсуждение абсолютно в каждом топике на хабре, хоть как-то связанном с фронтендом, вы так или иначе сводите к своему движку. Но, елки палки, сделайте нормальные selling туториалы с описанием как решать стандартные наболевшие проблемы. Роутинг, сайд эффекты, композиция компонентов, переиспользование компонентов, вы же понимаете о чем я.

Вердикт: вместо того, чтобы распыляться тут в комментариях, пишите больше статей в ключе практического применения своего решения.
Но, елки палки, сделайте нормальные selling туториалы с описанием как решать стандартные наболевшие проблемы.

У меня всего 2 руки и нет единомышленников. Туториалы я пишу по мере возможности. Но думаю дело пошло бы быстрее, если бы вы озвучили с какими конкретно трудностями столкнулись, чтобы я раскрыл эту тему подробнее.


Роутинг: https://github.com/eigenmethod/mol/tree/master/state/arg
сайд эффекты — тут что имеется ввиду?
композиция компонентов, переиспользование компонентов: https://github.com/eigenmethod/mol/tree/master/view

Ну а пока вы ужинаете, немного аналитики...


Итак, выводим семьсот с мелочью круглячков в форме треугольника серпинского, каждый из которых раз в секунду меняет содержимое, а всё целиком ресайзится каждый фрейм.


React


image


Реакту становится очень плохо, так как его архитектура заставляет его делать кучу лишней работы каждый фрейм.


React Fiber


image


Лишняя работа никуда не делась, но теперь она равномерно размазана по фреймам. При этом если пользователь начинает возюкать над круглечками, то обновление их содержимого замирает.


$mol


image


Так как архитектура ориентирована на минимизацию лишних вычислений, то даже без "квантификации рендеринга" мы более чем укладываемся во фрейм. Разве что раз в секунду происходит дроп одного фрейма из-за массового обновления содержимого всех узлов, но это не заметно для пользователя. На возюканье мышью реагирует быстро и обновление содержимого круглячков не останавливается.


Я даже пробовал прикрутить "квантификацию", причём не только рендеринга, но и вообще всех вычислений, чтобы анимации не подтупливали, когда рендерится что-то огромное, но это приводило к общему замедлению рендеринга (квантификация не бесплатна) и глюкам типа как у react fiber, когда возюкаешь мышью и часть страницы замирает. В результате вернулся всё же на вариант с полным обновлением за раз.

Может быть графика и вывод UI — это разные задачи? В gamedev'е отдельный поток на рендер — вроде как стандарт. Мне кажется, что рисование 100500 треугольников с помощью вращающихся кружков — вообще не кейс использования реакта

Не такие уж они и разные на самом деле. Вообще, кейс не мой, а написан для демонстрации преимуществ react fiber перед react: https://github.com/claudiopro/react-fiber-vs-stack-demo На всяких конференциях только его и показывают.

Спасибо за ссылку, хотя 50 неоднородных компонент на странице — это редкий случай.
Пример: есть панель со списком вложений. Рядом с именем файла крестик (удалить). Передать компонентам нужно свойство readOnly, контейнерную функцию (clickOnKrestik) и что-то статичное. Зачем здесь redux?
Я не против сторе, я против того, чтобы делать ВСЕ на редюсерах.
Задача: нужно сделать 6 панелей с однотипными компонентами и наваять из них около 20 форм для работы с БД. Связь родитель/ребенок, все просто и понятно, никаких mapDispatchToProps и mapStateToProps.
SPA вовсе не означает, что все должно быть на одной странице в одном контейнере.

Повсеместно применяю функциональные (stateless) компоненты. Изобрел вот такой велосипед:


export const pureComponent = (fn) => {
  class Wrapper extends React.PureComponent {
    render() {
      return fn(this.props, this.context)
    }
  }
  // не надо, т.к. подписывает на контекст как и функциональный компонент,
  // так и оболочку-PureComponent; лучше назначать сразу оболочке (снаружи)
  // Wrapper.contextTypes = fn.contextTypes
  Wrapper.displayName = fn.name
  return Wrapper
}

И теперь нужно следить только за props-ами.


Ещё разглядывал сегодня redux-persist, например. Для PWA сгодится.

Sign up to leave a comment.

Articles