Будни разработчика
14.7K subscribers
1.17K photos
333 videos
7 files
2.01K links
Блог Lead JS-разработчика из Хельсинки
Автор: @bekharsky

По рекламе: https://telega.in/channels/htmlshit/card?r=GLOiHluU или https://t.me/it_adv

Чат: https://t.me/htmlshitchat

№5001017849, https://www.gosuslugi.ru/snet/679b74f8dad2d930d2eaa978
Download Telegram
#инструмент дня

Что-то я насмотрелся на мучения семьи и коллег в отношении составления резюме, и решил поискать, а нет ли готовых бесплатных решений?

Кроме экспорта из линкедина, конечно.

Кругом какие-то скрытые подписки, ограниченные платные скачивания, дурацкие шаблоны...

С одной стороны, можно и Google Docs обойтись. С другой, процесс оттачивания резюме в процессе поиска работы может, мягко говоря, раздражать. HR'ы нынче капризные, хотят опыт и баззворды только под нужную вакансию, а больше ничего не хотят.

И такой инструмент нашёлся! Reactive Resume: https://github.com/AmruthPillai/Reactive-Resume

Открытый проект на React и Nest.js на бакенде. Можно запустить локально, можно захостить. А можно воспользоваться и сайтом: https://rxresu.me/

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

В общем, счастье соискателя — вот оно, рядом. Да и к контрибушенам проект открыт :)

#nestjs #react #resume
1👍164
This media is not supported in your browser
VIEW IN TELEGRAM
#заметка дня

Джордж Моллер (George Moller) — техлид в Shopify — предлагает интересное решение одной наболевшей в React проблемы. И проблема эта — ререндер всех компонентов, зависящих от некоего контекста.

Ну просто потому что useContext сработает на любое изменение данных в контексте, очевидно.

И решение это — кастомный хук useContextSelector: https://github.com/dai-shi/use-context-selector

И вроде всё бы ничего, вот только если вам пришлось это делать — вы используете контекст не очень верно. И лучше бы перейти на Jotai, Zustand, Effector, Reatom и так далее. На любой современный стейт-менеджер, короче говоря.

Контекст — он для чего-то глобального. Тема, данные пользователя, информация о лицензии. Плюс, совсем не обязательно хранить огромный контекст на всё приложение. Можно иметь много контекстов на разные зоны ответственности — в этом же вся его прелесть.

Но если уж вы попали в подобную ситуацию — да, useContextSelector спасёт.

Хотя я бы не стал.

#react #context #hook
🫡7👍42
#видео и #статья дня

Отгадайте за секунду, что это такое зелёное подсвечено на скриншоте Танков?

Да, это буквально игровой UI. А что если я скажу вам, что он написан на TypeScript и React?

А вы что думали, Реакт ограничивается только вебом и мобилками? Нет :) И Prabashwara Seneviratne (я не уверен, как его имя транслитерировать правильно) несколько лет назад как раз работал в отделении Wargaming в Праге над UI для World of Tanks.

И даже написал об этом статью: https://www.frontendundefined.com/posts/essays/pc-game-ui-react/

В статье вы найдёте не только некоторые технические подробности, но и узнаете, в чём фундаментальное отличие Web от игровых UI.

И таки да, вы не поверите, но там буквально свой кастомный браузер, поддерживающий лишь некоторые возможности HTML/CSS и JS.

Если лениво читать, автор не поленился выложить видео с конференции Web Expo 2022, где он рассказывает, в общем, о том же: https://www.frontendundefined.com/posts/talks/web-tech-game-ui/

#game #wot #react #ui
14👍8
#проект дня

Не так давно проходила выставка в Смитсоновском музее американского искусства и на ней была представлена целая стена из ЭЛТ-телевизоров. Почему-то на это обратил внимание твиттер FPGA Gaming (я просто очень эмуляторы люблю).

И я подумал: «А чем я хуже?» Тем более, что лет 8 назад мы делали проект для одного энергетического напитка, в котором был буквально ровно похожая идея. И они решили повторить её и на своём сайте.

Сайт уже давно поменялся, но подготовленные к проекту изображения у меня остались. По прошествии такого количества времени — зачем пропадать красоте, верно?

Итак, вашему вниманию совершенно бесполезная, но такая забавная, пирамида из телевизоров: https://bekharsky.github.io/tvs/

На айфонах не открывайте ссылку пока, я позже переделаю загрузку видео :) С автоматическим проигрыванием видео в мобильном Safari всегда были проблемы.

Что же понадобилось для сборки?

Первым делом, естественно, нужно собрать кадры аналоговых глюков воедино, чтобы получилось несколько видео. Их и будем запускать:


ffmpeg -f image2 -r 25 -pattern_type glob -i '*.png' -vcodec libx264 -crf 22 video.mp4


После чего подготовим наш список видео и подумаем: а что нужно сделать-то?

Простой запуск всех видео разом даёт интересный, но быстро надоедающий результат. Видеть подобное, например, на заставке — банально скучно. Очевидно, нужно запускать видео рандомно.

А лучше не просто рандомно, а ещё и сами видео на телевизорах менять!

И тут нам помогут вечные друзья: raf и ref.

В смысле, requestAnimationFrame и reference в React. А не то, что вы подумали.

С помощью requestAnimationFrame добиваемся рандомного запуска в пределах от секунды до трёх, а с помощью массива рефов — просто подменяем src видео в цикле.

Кстати, забавный трюк:


<video
ref={(el) => (videoRefs.current[i] = el)}
className="video"
key={`video-${i}`}
src={name}
loop
muted
/>


Проп ref представлен в виде функции, ref callback:

ref={(el) => (videoRefs.current[i] = el)}


В этот момент React присваивает ссылку на ноду элементу массива. Это хорошо описано в документации и не только экономит число ссылок и использований useRef, но и позволяет динамически этим списком управлять.

Ну и осталось — а осталось только запустить несколько рандомных видео и вовремя остановить их.

Повторю, на айфонах не всё так просто, поэтому запуск видео там я отложил на потом.

Исходный код, как всегда, доступен: https://github.com/bekharsky/tvs

Кстати, чтобы сделать эффекты ещё более интересными, можно не в видео их собирать, а перебирать картинки на лету. Что даст абсолютный контроль над кадрами. Чем, наверное, и займёмся вскорости.

Задавайте ваши ответы, котаны :)

#react #art #ref
3👍2
#проект дня

Мы прошлым летом проводили отпуск в Валенсии. Целью был более пляжный и гастрономический отпуск, нежели любование музеями и природой, потому поселились в районе, который когда-то представлял из себя рыбацкую деревню — Эль Каваньял (El Cabanyal).

Этот бывший рыбацкий квартал славится домами, украшенными азулежу — расписными глазурованными плитками. Они служили не только украшением, но и защитой стен от влаги и солнца.

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

Меня настолько эти плитки и эта традиция восхитили, что я посвятил несколько прогулок по жаре +40 только их фотографированию.

К сожалению, сфотографировать и сами дома тоже мозгов не хватило.

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

Итак:
1. Собираем фотографии в каталоге
2. Вычленяем из них геоданные
3. Находим в интернете векторный файл пина на карте, для маски, и готовим картинки маркеров и миниатюры.
4. Выводим всё на карте используя библиотеку React Leaflet.

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


const sortedTiles = [...tiles].sort((a, b) => a.lat - b.lat || a.lng - b.lng);
const majorityStart = Math.floor(tiles.length * 0.3);
const majorityEnd = Math.ceil(tiles.length * 0.7);
const majorityTiles = sortedTiles.slice(majorityStart, majorityEnd);


Код в репозитории:
💻 https://github.com/bekharsky/el-cabanyal-tiles

Ну и сама карта, конечно же!
📌 https://bekharsky.github.io/el-cabanyal-tiles/

Кликаем на маркер, а потом перемещаемся по ним клавиатурой.

Мне дико обидно, что я заодно не сфотографировал дома (впрочем, я потом пройдусь по архиву, что-то было же точно), но мне всё равно очень нравится то, что получилось. Какой-никакой музей :)

#spain #valencia #tile #react #leaflet
12👍1910🤡1
#инструмент дня

Серверные компоненты React в Parcel.js уже здесь!

Недавно я писал новость о выходе Parcel 2.14.0, который бросает вызов (нет) Next.js и внедряет у себя поддержку серверных компонентов!

И вот, мы дождались примеров!

Тут: https://github.com/parcel-bundler/rsc-examples

1. С сервером
2. Генерация статики — это, пожалуй, моя любимая и довольно недооценённая возможность
3. Клиентские, когда серверные компоненты рендерятся как обычные, интегрируясь в уже сущестующее приложение.

В общем, наконец-то можно нормально пощупать без того, чтобы тянуть весь Next.js. Я очень рад.

#parcel #rsc #react
👍41
This media is not supported in your browser
VIEW IN TELEGRAM
#инструмент дня

Мой самый любимый виджет из всех — Modal Bottom Sheet. Это как в построении маршрута на Google Maps. Шторка, по-нашему. Дёргаешь её туда-сюда, забавно.

Так вот, в мобильных фреймворках вроде того же Flutter и SwiftUI шторка реализована из коробки, а для веба — приходится изгаляться.

Хотя у шторки на мобильных устройствах очень много на самом деле общего со множеством других виджетов: модалка, тост, боковое меню, лайтбокс, стек (как в Tinder). Просто потому что их очень интуитивно можно смахнуть или развернуть жестами.

Так вот, собственно, к чему это я: https://silkhq.co/

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

Множество примеров, нативные анимации, жесты. Одна проблема: платная для коммерческого использования. И не открытая.

Две, получается, проблемы :(

P. S. В комментариях пишут, что так-то три проблемы. Третья — React. Штош.

#react #sheet #widget
👍14🫡31
Media is too big
VIEW IN TELEGRAM
#инструмент дня

Охренеть какая штука!

https://react-explorer.com/

Это обозреватель зависимостей. Я бы даже сказал, созвездия завимимостей и сейчас вы поймёте, почему.

Потому что помимо простого дерева, которое в целом умеет строить кто угодно, тут имеется мини-карта!

Перемещаешься по карте — смотришь подсвеченные созвездия. Инспектор работает на любом реакт-сайте без отдельной установки, потому что построен по принципу React Scan — инджектит React DevTools на страницу.

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

Проект пока не открыт, но находится в открытом тестировании.

#react #analyze #dependencies
22👍1
#заметка дня

Не знаю, как вас, но меня очень раздражает то, что в React Router состоянием скролла надо управлять самостоятельно.

Перемещаешься по роутам, а скролл на месте остаётся. Ну типа, што.

К счастью, решение что для v5 React Router, что для v6 одинаковое:


function ScrollToTop() {
const { pathname } = useLocation();

useLayoutEffect(() => {
document.documentElement.scrollTo(0, 0);
}, [pathname]);

return null;
}


И потом вставляете его в контекст роутинга:

<BrowserRouter>
<Routes>
...
</Routes>
<ScrollToTop/>
</BrowserRouter>


Но вот я это всё по привычке написал и решил всё-таки посмотреть документацию. Ну бывает. И вот что там: https://reactrouter.com/en/main/components/scroll-restoration

Восстановление скролла теперь поставляется из коробки! И умеет гораздо больше, чем просто скроллить наверх. Правда, требует изменения корневого роутера. Благо, это несложно.

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

По-моему, очень круто. И хорошо, что решение официальное.

#react #router #бородач
👍133🤡1
This media is not supported in your browser
VIEW IN TELEGRAM
#инструмент дня

Вы только посмотрите на эту красоту!

Да, я в курсе, что компонентов для красивого прокручивания цифр у нас какое-то невероятное количество, но до сих пор не было ничего настолько универсального и простого в использовании.

И не только для React! Vue и Svelte тоже там.

Итак, встречайте: NumberFlow от Максвелла Барвиана.

GitHub: https://github.com/barvian/number-flow
Документация и демо: https://number-flow.barvian.me/

Настраивается формат чисел, параметры анимированных переходов. И, собственно, никаких скрытых зависимостей.

Прекрасное.

#react #number #transition #бородач
31
Дэн «наше всё» Абрамов разродился статьёй!

React for Two Computers

— Почему мой компонент работает в браузере, но не на сервере?
— Потому что у тебя теперь два компьютера. Привыкай.

💥 Что вообще происходит?

Раньше React жил в браузере и радовался жизни: всё происходило на клиенте, стейт в useState, кликнули — перерендерили.

А теперь у нас появился второй «компьютер» — сервер. С серверными компонентами, приватными API, тяжёлыми вычислениями и всем остальным. И теперь React — это не просто `f(state)`, а f(data, state), где:

- data — с сервера, рендерится один раз
- state — в браузере, реагирует на действия пользователя

🧠 React теперь работает в двух мирах:

- Сервер — отвечает за данные, безопасность и тяжёлую работу
- Клиент — за мгновенные отклики, интерактив и состояние

Они живут в разных средах, но должны строить один интерфейс. И вот тут начинается веселье.

🧩 Но в чём подвох?

Абрамов говорит прямо: разделение компонентов на клиентские и серверные — это боль.

- Хочешь использовать хук? Прости, сервер не умеет
- Хочешь загрузить данные? Сервер умеет, но клиент не должен знать как
- Хочешь просто написать код? Удачи с этими use client, use server, границами, пропами и тайпингом

🧠 Примеры из статьи

- <Counter /> — типичный клиентский компонент. Быстрый отклик, стейт, интерактив
- <PostPreview /> — серверный. Может грузить пост из базы и вообще не попадать в бандл клиента

И вдруг возникает челлендж: а как показать список <PostPreview />, а рядом <Counter /> для лайков? Как они будут жить вместе?

Ответ: через пропсы, границы, и много боли.

📦 React как Lego из серверных и клиентских кусочков

Абрамов не просто жалуется — он исследует. Он пытается найти модель мышления, при которой:

- Ты не дублируешь код
- UI остаётся отзывчивым
- Компоненты переиспользуемы
- И при этом ты не хочешь сжечь проект через неделю

Он говорит: возможно, будущее React — это когда мы думаем не в терминах "компоненты", а в терминах "где этот кусок должен жить?"

🎥 Есть и видео!

Если лень читать или хочется живого контекста — Дэн рассказал всё это на конференции React Conf 2024.
Там много примеров и визуальных пояснений.

🧨 Финалим

«React теперь не просто библиотека для UI. Это **координация между двумя средами исполнения**. Между клиентом и сервером. И это сложно. Но в этом сила.»

Пока что — это боль.
Но если мы научимся думать в этой модели — React станет по-настоящему мощным инструментом для приложений нового поколения.

🔗 Читать статью целиком

📺 Смотреть видео React Conf 2024

#react #frontend #абрамов #servercomponents
1🤡14👍123🫡1
Media is too big
VIEW IN TELEGRAM
#инструмент дня

Так вышло, что в своей карьере я умудрился поработать в компании, которая хотела сделать стримы на веб-сайте своей основной фишкой. С тех пор HLS, RTP и nginx-rtmp-plugin были моими друзьями.

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

Но сегодня я наткнулся на нечто прекрасное: https://compositor.live/

Это набор React-компонентов и медиасервер, который позволяет стримить видео и микшировать несколько потоков, управляя ими как обычными компонентами и элементами страницы!

Можно построить нечто аналогичное Google Meet за считанные дни.

Вырезать зелёный экран, добавить текст, поменять видео местами, наложить блупер — всё на месте. Напоминает react-three-fiber по своей сути.

#react #video #mixer #media #stream #бородач
👍268
#статья дня

Дэн наше всё Абрамов недавно написал статью о новом способе передачи данных с сервера — Progressive JSON. Это не просто использование курсоров для пагинации, как в том же JSON:API, а настоящий поток данных, где структура JSON передаётся частями, по мере её готовности.

Вообще, много пишет последнее время. Это хорошо!

Зачем нужно? Собственно, для работы React Server Components в том числа!

Пример такого потока:

{
"header": "Welcome to my blog",
"post": "$1",
"footer": "Hope you like it"
}

Видите заглушку $1? Позже — в том же потоке! — приходит следующий кусок:

/* $1 */
{
"content": "This is my article",
"comments": "$2"
}

На стороне клиента это будет выглядеть как:

{
"header": "Welcome to my blog",
"post": {
"content": "This is my article",
"comments": new Promise(/* ... not yet resolved ... */),
},
"footer": "Hope you like it"
}


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

Если вам интересна тема оптимизации загрузки данных, стоит прочитать статью Дэна: Progressive JSON.

А, или посмотреть в формате видеоподкаста! Тут: https://www.youtube.com/watch?v=MaMQLNBZz64

#react #json #rsc
👍226👎2
#статья дня

Можно ли заменить стейт-менеджеры — простым localStorage?

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

Давайте подумаем:

> Не всё должно быть постоянным. Допустим, у тебя открыто модальное окно. Перезагрузил страницу — и оно снова открыто, потому что значение сохранилось в localStorage. Абсурдный UX.

> Нет реактивности. Если просто читать из localStorage, React не узнает, что данные изменились, и не перерендерит компонент. Придётся вручную дёргать setState.

> Событие storage работает не так. Оно срабатывает только в других вкладках, а не в той, где ты вызвал localStorage.setItem(). То есть синхронизацию внутри приложения оно не решает.

> Ограничения. Только строки, лимит около 5 МБ, возможные ошибки при парсинге JSON, коллизии ключей. Всё это требует дополнительных костылей.

> SSR недоступен. На сервере localStorage просто не существует, и код падает с ошибкой.

localStorage и, частично, sessionStorage отлично подходят для мелочей:

> выбор темы,
> сохранение введённых данных формы,
> открытая вкладка меню,

Но как только речь заходит о данных, которые должны синхронно обновляться в разных компонентах и вызывать ререндер — нужен Context или полноценный state-менеджер.

Итак: localStorage — это удобное дополнение к Context/Redux/Zustand, но не замена. Он решает задачу «сохранить между сессиями», а не «синхронизировать состояние внутри React».

А если хотите подробностей — собственно, статья от Нади Макаревич: https://www.developerway.com/posts/local-storage-instead-of-context

Не думаю, что олды что-то найдут новое (разве что лишний раз поржать над событием storage), но у новичков вопросы такого плана возникают постоянно.

#react #localstorage
6
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня

И #тред дня, и #статья дня... Сегодня всё и сразу от Джоша Комо.

И речь пойдёт о недооценённом хуке в React: useDeferredValue.

Итак, некоторое время назад Джош выпустил свой инструмент для создания красиво выглядящих теней (да-да, drop-shadow просто уже недостаточно). И одной из проблем инструмента стала... дёрганая реакция на движение ползунков. Как будто мало FPS.

Начав разбирать проблему, Джош понял, что событие onChange происходит очень часто, за это время надо успеть сгенерировать тень, потом отрисовать её, потом вставить код в редактор для копирования. А редактор, естественно, ещё пытается этот самый код подсветить.

Но что нам нужно? Нам ведь сначала нужен результат, а уже потом — код. Так почему бы не заполнить код чуть позже, не нагружая систему?

И именно для этого и нужен хук useDeferredValue. Данные молучим только когда основной процесс рендеринга завершится. Буквально ленивое выполнение.

Собственно, тред и статья если кто предпочитает подробности. Там, как всегда, шикарно.

Будьте разумно ленивыми, котаны!

#react #hook #бородач
18