Библиотека фронтендера | Frontend, JS, JavaScript, React.js, Angular.js, Vue.js
21.8K subscribers
2.79K photos
192 videos
43 files
5.11K links
Все самое полезное для фронтенда в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/77178ed4

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5b6884689c2151c820bb4
Download Telegram
😱 Потерянный this в обработчике

Когда метод объекта передаётся как колбэк, он теряет контекст (см. фото). После клика в консоли будет undefined.

Почему так:

this зависит от способа вызова функции, а не от места, где она объявлена.

При передаче метода как ссылки (btn.handleClick) контекст теряется — this больше не указывает на объект.


Как исправить:

1. Явно привязать контекст


button.addEventListener('click', btn.handleClick.bind(btn));


2. Использовать стрелочную функцию


button.addEventListener('click', () => btn.handleClick());


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

#hotfix #js
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰63👍3
😱 React-баг, который ловят не все

Кажется, простой счётчик — но React со своим batching (см. на картинке).

Ждём 2 Получаем 1

💡 Почему так:

React группирует (batch) обновления состояния внутри одного события. Обе строки читают старое значение count из замыкания, поэтому результат — 1.

Решение:

Если новое состояние зависит от предыдущего — используйте функциональное обновление 🔜


setCount(prev => prev + 1);
setCount(prev => prev + 1);
Теперь результат будет 2.


React работает по снимкам состояния, а не по «живым» переменным — и именно это часто сбивает с толку.

🐸 Библиотека фронтендера

#hotfix #react
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰6👍3
😓 100vh съедает половину экрана на мобилках

Классика: делаешь height: 100vh для фуллскрин-секции, на десктопе всё ок, а на телефоне контент уезжает за экран и появляется скролл.

В чем причина:

Браузер считает 100vh по полной высоте экрана, включая скрывающиеся панели. Когда скроллишь — адресная строка прячется, высота viewport меняется, и блок начинает прыгать.

Раньше приходилось считать реальную высоту через JS — решение рабочее, но костыль.

🔤 Теперь есть нормальные CSS-единицы (с 2022 года):

dvh — динамическая высота, подстраивается при скролле

svh — учитывает адресную строку

lvh — без адресной строки, максимальная высота


Поддержка: iOS 15.4+, Chrome 108+, Safari 15.4+

Fallback:

Сначала указываем height: 100vh, а следом height: 100dvh — новые браузеры просто переопределят старое значение.

🐸 Библиотека фронтендера

#hotfix #css
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18🥰5❤‍🔥41
🔥 Props через 5 уровней — рефакторим через children

➡️ Проблема (1 картинка):

Передаём user через Dashboard и Sidebar, хотя они его не используют. Компоненты становятся «курьерами» для чужих данных.

➡️ Решение (2 картинка):

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

Что это даёт:

🟡 Без prop drilling — данные идут напрямую к UserProfile
🟡 Dashboard и Sidebar становятся переиспользуемыми
🟡 Меньше связности, проще тестировать и поддерживать

Когда что использовать:

Композиция — данные нужны только конечному компоненту
Context API — данные нужны многим компонентам на разных уровнях (theme, auth, locale)

🐸 Библиотека фронтендера

#hotfix #react
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍32👏1
😓 Роутинг в SPA — боль

Классика: слушаем click, ставим preventDefault(), делаем history.pushState(), потом ловим popstate и рендерим контент.
Работает, но это куча бойлерплейта и расхождений между состоянием, URL и историей.

Почему так:

History API не создавался под SPA. Он не умеет централизованно управлять всеми типами навигации и не даёт понять, когда переход «завершён», чтобы безопасно менять UI и скролл.

🔤 Нормальное решение — Navigation API (эксперимент, Chrome 102+):

• navigate — единое событие для всех переходов
• event.intercept() — перехват и свой обработчик (загрузили данные, отрисовали, проверили доступ)
• event.scroll() — нативный скролл
• { committed, finished } — когда менять URL и когда переход реально завершён
• entries() и currentEntry — история как нормальные объекты со state


Fallback:

Если window.navigation нет, остаёмся на старом pushState.


if ('navigation' in window) {
navigation.addEventListener('navigate', (event) => {
if (shouldNotIntercept(event)) return;
const url = new URL(event.destination.url);

event.intercept({
async handler() {
renderSkeleton();
const html = await fetchPage(url.pathname);
render(html);
event.scroll();
},
});
});

const { committed, finished } = navigation.navigate('/profile');
committed.then(() => showLoading());
finished.finally(() => hideLoading());
}


📦 Поддержка:

Chromium 102+, Safari (новые версии), Firefox — пока нет.
API экспериментальный, используйте feature-detect.

📎 Официальная спецификация

🐸 Библиотека фронтендера

#hotfix #js
Please open Telegram to view this post
VIEW IN TELEGRAM
🥰53🔥1