Это произошло в понедельник 13 февраля, мир больше не будет прежним. Открыта вакансия:
Для работы над нашими проектами мы ищем сильного front-end разработчика. Вам предстоит амбициозная задача: внедрить компонентный подход в разработку всех текущих и новых проектов компании.
Отлично, работаем дальше! Выполняю "тестовое задание".
Процесс переноса нашего любимого сайта в react-компоненты черезвычайно прост. Нужно кликнуть кнопку [квадратик со стрелочкой курсора] в Chrome DevTools, скопировать выбранный HTML-блок в файл temp.html, добавить аттрибуты вида data-component="MyReactComponent" к будущим компонентам, и запустить в консоли:
> html2react ./temp.html
Результат в ./components/ — готовые JSX-скрипты.
В чем прелесть компонентов? Декомпозиция задач более очевидна, оценивать трудозатраты можно точнее, в итоге проще управление процессом разработки. Постепенно сформируется понимание, как разделять блоки верстки на компоненты: просто много кода на один компонент, какой-то интерактив, дополнительный функционал. Главное пока не увлекаться, первая задача — Minimum Viable Product (MVP).
Ох, сколько же бывалых веб-разработчиков оттолкнула каша из HTML-тегов внутри JavaScript-кода. У меня аллергия прошла через три года, а тут ещё ES6 подоспел — кошмар ретрограда. Но всё к лучшему, за это время экосистема React-а выросла и окрепла. Как раньше люди жили без Redux-а, наверно мучились. :)
Отличная штука create-react-app, избавляет от небходимости настройки node-приложения на текущем начальном этапе, при том что не навязывает ничего лишнего.

И вот появилась первая страничка Хабра на localhost:3000 почти неотличимая от оригинала — это щастье!
Встречаются и ошибки в верстке, и legacy-блоки; код требует вдумчивого просмотра и редактуры. Заменил ссылки по шаблону "https://habrahabr.ru/" на "/#/", благо они почти везде абсолютные. Подключил @font-face, восстановил работоспособность плашки "#scroll_to_top".
// Переписал вызовы
<a ... onclick="if (typeof ga === 'function') { ga('send', 'event', 'footer', 'links', 'ios_app'); }" >
// на новый лад
<a ... onClick={ga.bind(void 0, 'footer', 'links', 'ios_app')} >
// и добавил функцию
export const ga = (eventCategory, eventAction, eventLabel) => {
if (typeof window.ga === 'function') {
window.ga('send', 'event', eventCategory, eventAction, eventLabel)
}
}
Задействую Redux, пока наполнил фейковые данные в initialState. Уже можно добавить новую статью из формы в Store. Сделал некоторые статические страницы по ссылкам из колонки "Инфо" в подвале, роутинг работает сносно, но требуется реализовать крошки в разделе "Помощь". Применяя "react-helmet", разблюдовал подключение css-файлов (т.к. страница 404 оформлена иначе). Использую "reselect" (пример в components/PostTeaserList.js — фильтр по потокам), "redux-act" (пример в reducers/editPost.js). Для обработки сайд-эффектов подключил "redux-thunk". Инлайновые стили добавляю с помощью "styled-components" (пример в components/InfoHelpPost.js).
Общее правило — не зацикливаться на деталях. Если задача не решается за 15 минут, или просто отвлекает, то откладываю с пометкой TODO. Есть мнение, что 85% времени занимают мелкие доработки. Важно быстро вырастить скелет, а наращивать мясо — последующие этапы через итеративную непрерывную интеграцию.
PS
Если вам нужно быстро реинкарнировать старое веб-приложение, тогда примерьте модный компонентный подход (привет, Delphi'95 & Rapid Application Development).
Леонид Аркадьевич, пользуясь случаем, ещё передаю приветы Mail.ru и Fast Line Ventures; упрощается "адаптация" успешных забугорных проектов. Кстати, для инди-разработчиков это способ поднять свой маленький свечной заводик: экономия на ТЗ, на дизайне, на верстке. Помните, что идеи ничего не стоят? Реализация тоже подвержена удешевлению.
Описанный метод переноса верстки в react-компоненты отлично применим и для текущих проектов на React, если ваша команда разделена на верстальщиков и разработчиков.
Когда хочется освоить новую технологию (например React), то лучший метод обучения — это копирование существующего проекта с использованием требуемой технологии. Как минимум, для портфолио на GitHub. Исходники проекта обновляются тут.
Демо: yobr.ru
Комментарии (49)
vintage
18.02.2017 10:40+2При переходе между страницами сначала появляется контент, а только чрез пол секунды — к нему подцепляются стили — всё очень неприятно скачет. И это на одностраничном сайте.
Добавление поста не работает, да и выглядит паршиво. Не удалось реализовать за 15 минут?
Я так и не понял, зачем вам тут потребовался реакт, чтобы нарисовать несколько статичных html-шаблонов, практически без динамики.
comerc
18.02.2017 11:16-1При переходе между страницами сначала появляется контент, а только чрез пол секунды — к нему подцепляются стили — всё очень неприятно скачет. И это на одностраничном сайте.
Подправил костылем, как заставить Helmet подключать стили правильно — может кто подскажет?
comerc
18.02.2017 11:20Добавление поста не работает
F12, после отправки формы нужно смотреть сюда:
Я говорил про добавление в Store.
vintage
18.02.2017 11:37А что толку от добавления в стор без обновления интерфейса?
А helmet правильно стили добавляет, но делает это динамически, во время рендеринга. Очевидно, для продакшена такой подход не годится.
comerc
18.02.2017 12:42А helmet правильно стили добавляет, но делает это динамически, во время рендеринга. Очевидно, для продакшена такой подход не годится.
пробовал бороться с ним вот так, локально помогало, а в продакшене опять беда:
componentWillMount() { document.body.style.display = 'none' } componentDidMount() { // HACK стили подключаются в Helmet после рендеринга страницы setTimeout( () => document.body.style.display = 'block' , 100) }
VolCh
18.02.2017 13:14react-helmet, по-моему, слабо заточен на работу с ресурсами, требующими загрузки. Для них нужно маунтить основной компонент, когда ресурс уже загружен (чего может вообще никогда не произойти, например из-за 404). Он хорошо работает, когда нужно не внешний стиль/скрипт подключить, а прямо в тегах style/script писать css/js. А чем вам что-то вроде
import React from 'react'; import styles from './styles.css'; export default class HabrPage extends ReactComponent {...};
не нравится?
comerc
18.02.2017 13:26Правильная постановка вопроса — половина решения. Нужно отловить момент загрузки скриптов в Helmet!
А чем вам что-то вроде не нравится?
Всё дело в том, что для 404 на Хабре подключаются другие стили (смотри /components/NotFound.js). Т.е. нужно было как-то разблюдовать. Импорт же подключает стили в проект намертво. Есть мысли подгружать саму страницу динамически, используя require.
VolCh
18.02.2017 13:44+1А как-то так:
import React, { Component } from 'react' import Helmet from 'react-helmet' import styles from './../../public/styles/access_deny.css' class NotFound extends Component { render() { return ( <div id="layout"> <Helmet defaultTitle="Хабрахабр" /> <div className={styles.main}> <div className={styles.logo}> <a href="/#/" title="На главную страницу"><img alt="" src="https://habrahabr.ru/images/logo.svg"/></a> </div> <h1>Страница не найдена</h1> <p>Страница устарела, была удалена или не существовала вовсе</p> <div className={styles.buttons}> <a href="/#/" className={styles.button}>Вернуться на главную</a> </div> </div> </div> ) } }
Вообще говоря, компонентный подход предполагает, что и js-код, и разметка, и стили хранятся если не в одном файле (есть любители CSS в JS непосредственно писать, но меня они в удобстве подхода не убедили), то очень близко друг от друга, как-то так:
src/components/NotFound/index.js
src/components/NotFound/styles.css
При переделке существующего приложения на реакт, я просто в каталог каждого компонента копировал все стили, импортировал их в JS, а уж потом в каждом отдельном компоненте вычищал лишнее.
comerc
18.02.2017 13:56Спасибо, до меня дошло! За лесом не видно деревьев. Так можно тупо переопределить стили для каждого HTML-тега в компоненте NotFound.
VolCh
18.02.2017 14:01Так можно определить стили вообще для каждого компонента и забыть про них в других местах :)
comerc
18.02.2017 14:09Так и было сначала, использовал другую утилиту для извлечения компонентов. Но она не понимает русские буквы и для каждого компонента добавляет id, а если id были определены в первоначальной верстке, то их затирает. В морг.
shybovycha
18.02.2017 13:37+2Судя по комментариям в этом треде, напрашивается мысль "I had 99 problems. Then I used React. Now I have 101 problem."
В чем суть статьи? Показать, как худо-бедно сделать драфт? Или как использовать все вышеперечисленные библиотеки (react-helmet, redux-act, redux-thunk)? Но ведь ничего из этого нету в статье...
comerc
18.02.2017 13:49-2Пока не хватает примера только для redux-thunk. Остальное все есть в исходниках, в статье указано, куда смотреть.
shybovycha
18.02.2017 13:54Ну так почему бы не не уместить это все в статью?
comerc
18.02.2017 14:04Первые пять минут фильма "Быстрее пули" со Скалой — шедевр. Потом всё скатилось, как обычно.
Краткость — сестра сами знаете чего.
shybovycha
18.02.2017 14:08+4По-моему вы не поняли, что я пытаюсь донести. Высказывание "краткость — сестра таланта" хорошо работает для Твиттера. На блогах вроде Хабра или Медиума, как мне кажется, пользователи хотят видеть статьи, раскрывающие какую-либо тему. Ссылку на репозиторий гитхаба можно уместить и в 140 символов.
andreylat
18.02.2017 17:42+1Я правильно понял, что это все только фронтэнд без серверной части и сохранения?
comerc
18.02.2017 18:46Именно, и в этом вся прелесть. Есть конечно SSR, благодаря которому сможешь работать, как в привычном PHP. Но в данном примере все выполняется на клиенте. Если собрать под Electron-ом, то получим кросс-платформенное десктоп-приложение. Если заменить React на ReactNative, то получим мобильное приложение. Благодаря Redux-у, определена архитектура круговорота данных в приложении. Дальше нужно подключиться к внешнему REST-API или Websocket-серверу. И можно купить backend, как услугу, засматриваюсь на scorocode.ru
novoselov
18.02.2017 18:17+1Ох, я уже и забыл как выглядит «нативный» хабр :)
StyleBot уже давно скрывает все мусорные блоки, объявления, кросс-ссылки.
Жаль родительский сайт для сохранения скриптов лежит, кто-нибудь знает достойные альтернативы StyleBot?
denismaster
В том то и дело, что каша из кода и тегов — это далеко не серебрянная пуля, как бы React не был хорош. Да, модно, да, решает задачу, но всегда найдется альтернативный подход, а у него — сторонники.
comerc
Беда в том, что нет единственно правильного ответа. Пока React победил в моих изысканиях. Предыдущая ставка на Meteor — потерянное время.
vintage
С нетерпением ждём следующей серии в изысканиях :-)
comerc
Вообще-то я очарован Clojure. Но такую корову не продать.
S_A
Можете пару слов о Метеоре, пожалуйста? Начинаю на нём сейчас серьезный проект, интересны чужие грабли.
comerc
Слишком интимный вопрос, многих ранила моя статья эту тему. Отвечу в личку.
comerc
Хотя один камрад стойко преодолевает трудности.
S_A
Спасибо, очень полезно. Как-то упустил статью.
comerc
Вот это самая лучшая статья по React+Redux из тех, что я перелопатил. Три раза перечитывал. И постиг Дзен.
comerc
Ещё хочу дать самые лестные рекомендации проекту Monster Lessons: JavaScript, React, Redux. Превосходная подача материала!
movl
У меня был опыт работы с метеором только на внутренних проектах, и ни разу не разочаровался в нем. Из примеров — это приложение, интегрированное с основным проектом на рельсах, созданное для совместной обработки заказов пользователей, и приложение для администрирования нескольких игровых серверов (mongodb).
Мне понятно, что примеры достаточно специфичные, также стоит учитывать, что я писал их один. И также я представляю, что с проектами на метеоре может быть множество проблем. Но категорически не могу согласиться с проведением параллелей с React, эти инструменты решают разные задачи, причем могут это делать совместно, по моему мнению, метеор — это в первую очередь протокол клиент-серверного общения.
Из того, что мне очень нравится в метеоре: он дает высокую скорость при создании скелета приложения, дает возможность писать минимум серверного кода (и, как правило, синхронного кода) и дает данные в реальном времени на клиенте. Из специфичного, мне нравится blaze, и вообще, то как реализована реактивность на фронтэнде. Из главных минусов, по моему мнению: это то что все завязано на монге и ddp, и, как следствие, узкая область применимости, но это и есть суть фреймворка. Я не считаю, что клиентская часть приложения может быть проблемой в принципе, так как есть полная свобода в выборе инструментов, но, конечно, есть свои особенности, вытекающие из протокола. Также я не могу судить о возможных проблемах, связанных с высокой нагрузкой, но судя по различным публикациям в интернете — дела обстоят более-менее, и это уже индивидуальный вопрос для каждого проекта.
Сам бы я решился начать новый проект на метеоре, если нужны данные в реальном времени на клиенте, если не нужна сложная бизнес-логика и если монга подходит в качестве хранилища, со всеми вытекающими критериями. Наверное, такими условиями отбрасываются 95% проектов, если не больше, и, конечно, есть множество других вопросов, которыми стоит задаться при выборе. Но в общем случае, я считаю, что метеор хорошо подходит для приложений, где важна коллаборация в реальном времени, например: форумы, хелпдески, системы управления задачами и т. д.
Возможно из-за удачного стечения обстоятельств, но я не натыкался на как таковые грабли, связанные с метеором. Была особенность: одно приложение надо было завязать на множество различных баз данных, но решение с полпинка было найдено, причем с сохранением всех плюшек метеора. Периодически мне встречается мнение, что метеору место на помойке, с чем никак не могу согласиться, и имея опыт работы с ним, в будущем с удовольствием выберу его снова, если будет такая возможность и если будет подходящий проект. Это все несколько общие слова, но если есть конкретные вопросы, готов ответить в личных сообщениях.
S_A
Спасибо за развернутый комментарий!
Разделяю это мнение, правда кругозор в JS-фреймворках у меня не особо большой.comerc
Ваш коммент больше, чем моя статья. Спасибо за аргументы.