Список доступных хештегов:
Основные:
#theory — общая теория программирования, разбор теоретических вопросов с собеседования
#quiz — короткий вопрос на свободную тему в разработке с вариантами ответов
#useful — просто полезные вещи
#blog — посты в формате блога обо мне / на свободную тему
Подгруппы:
#javascript — всё, связанное с языком
#typescript — аналогично👆
#code — посты во встроенным в текст кодом, готовые примеры
#vite — посты, которые так или иначе затрагивают сборщик
#web — всё, касательно web разработки
#principles — принципы проектирования
#react — всё, касательно React
#patterns — всё о паттернах
#data — всё о данных и манипуляциях с ними
#news — новости
#python — всё, связанное с этим языком
#mobile — мобильная разработка
#design — штучки для дизайна
#github — интересности с гита
#chatbot — мои боты и всё, что с ними связано
Основные:
#theory — общая теория программирования, разбор теоретических вопросов с собеседования
#quiz — короткий вопрос на свободную тему в разработке с вариантами ответов
#useful — просто полезные вещи
#blog — посты в формате блога обо мне / на свободную тему
Подгруппы:
#javascript — всё, связанное с языком
#typescript — аналогично
#code — посты во встроенным в текст кодом, готовые примеры
#vite — посты, которые так или иначе затрагивают сборщик
#web — всё, касательно web разработки
#principles — принципы проектирования
#react — всё, касательно React
#patterns — всё о паттернах
#data — всё о данных и манипуляциях с ними
#news — новости
@deprecated
#python — всё, связанное с этим языком
#mobile — мобильная разработка
#design — штучки для дизайна
#github — интересности с гита
#chatbot — мои боты и всё, что с ними связано
Please open Telegram to view this post
VIEW IN TELEGRAM
Именованный и неименованный экспорт
Начнем с того, что экспорт бывает разный — именованный и неименованный.
Именованный экспорт — это использование ключевого слова
Стандартный же экспорт — это экспорт с использованием конструкции
Помимо разницы оформления каждого из способов экспорта в коде, также отличается и их импорт. В случае с именованным экспортом у нас есть возможность импортировать каждую сущность из файла по его названию:
Стандартный импорт:
А также их комбинация:
Но что насчет проблематики? Почему разработчики каждый раз сталкиваются с вопросом какой лучше экспорт выбрать?
Чтобы понять это, рассмотрим следующий пример:
В двух импортах выше видна основная проблема — неявные переименования. Такие переименования сущностей могут путать разработчиков, никак не защищают от опечаток, что в совокупности приводит к неоднозначности именований. Из-за всех этих проблем
Также к минусам
Всех этих проблем лишен именованный экспорт. Его обработка сравнительно быстрее, а имя сущности сохраняется на протяжении всего пути от экспорта до импорта, что устраняет возможные неоднозначности.
Мой вывод: я стараюсь сократить использование
Спасибо за прочтение, это важно для меня ❤️
#web #javascript #react #patterns
Начнем с того, что экспорт бывает разный — именованный и неименованный.
Именованный экспорт — это использование ключевого слова
export
перед каждой сущностью или при использовании «паттерна» export list
, когда все экспортируемые сущности перечисляются в одном месте файла:// именованный экспорт
export const a = 1
// export list
const c = 3
const d = 4
const f = 5
export {
c,
d,
f
}
Стандартный же экспорт — это экспорт с использованием конструкции
export default
:// стандартный экспорт
const b = 2
export default b
Помимо разницы оформления каждого из способов экспорта в коде, также отличается и их импорт. В случае с именованным экспортом у нас есть возможность импортировать каждую сущность из файла по его названию:
import {
Status,
getUser,
render as renderFunction
} from './file'
Стандартный импорт:
import React from 'react'
А также их комбинация:
import React, { useState, useMemo } from 'react'
Но что насчет проблематики? Почему разработчики каждый раз сталкиваются с вопросом какой лучше экспорт выбрать?
Чтобы понять это, рассмотрим следующий пример:
import Angular from 'react' // абсолютно валидно
import { Status as UserStatus } from './file'
В двух импортах выше видна основная проблема — неявные переименования. Такие переименования сущностей могут путать разработчиков, никак не защищают от опечаток, что в совокупности приводит к неоднозначности именований. Из-за всех этих проблем
export default
является инструментом, использование которого только усложнит поиск чего-либо по коду и его отладку.Также к минусам
export default
можно отнести то, что такие сущности индексируются статическими анализаторами медленнее и сложнее, что в больших проектах может повлечь за собой проблемы с линтингом.Всех этих проблем лишен именованный экспорт. Его обработка сравнительно быстрее, а имя сущности сохраняется на протяжении всего пути от экспорта до импорта, что устраняет возможные неоднозначности.
Мой вывод: я стараюсь сократить использование
export default
до минимума, предпочитая именованный экспорт и импорт. Использовать export default
валидно только для интеграции вашего кода с уже готовыми решениями, например, это может быть React.lazy
и React.memo
, которые работают только с export default
по умолчанию. У меня есть удобный хак как это обойти, но это тема для отдельного поста.Спасибо за прочтение, это важно для меня ❤️
#web #javascript #react #patterns
CSS можно в JS и это не всегда хорошо
Фронтендеры как будто не могут договориться как им хочется писать стили 🙂. Вариантов очень много, разнообразных препроцессоров и инструментов в виде библиотек стилей, CSS фреймворков…
Вообще, CSS-in-JS — это некоторый подход, в котором мы отказываемся от массового использования стандартных CSS файлов и пишем стили внутри JS. Для реализации этого концепта есть несчётное количество библиотек, но для React основной я бы назвал
Причина проста: это очень удобно, по нескольким причинам.
1. CSS-in-JS позволяет генерировать стили динамически для одного класса. Стандартный CSS так не может, мы должны изменять стили только добавлением дополнительного класса, модификатора и т.д.
2. Дополнительная мета-информация при разработке переезжает из
3. Упрощённая файловая структура. Формочки можно клепать ещё проще и быстрее, не переключаясь между файлами.
Возможно и звучит круто, но за всё это приходится платить достаточно высокую цену:
1. Стили создаются в рантайме и блокируют выполнение остального JavaScript на странице. Это приводит к проблемам с производительность, особенно для перегруженных систем. Всё это удобство в разработке приведет к тому, что пользователь будет плеваться от того, какое медленное приложение вы сделали.
Использование нативного CSS для браузера куда понятнее и быстрее, JS бандл становится меньше и грузится также быстрее, а стили подгружаются параллельно вашему коду.
В результате-то что? На мой вкус, CSS-in-JS — это и правда очень удобно. Но я полностью отказался от этого подхода в своих проектах, потому что не готов платить производительностью за все плюсы, что описал выше.
Если вы хотите писать стили быстро и качественно, то я действительно рекомендую обратить большее внимание на обычные модульные стили на каком-то препроцессоре или же вообще на Tailwind CSS. От последнего я, кстати, невероятно долго плевался, ну а потом как обычно: отрицание, гнев, торг, депрессия, влюбился… Точно рекомендую посмотреть, если ещё не пробовали)
Спасибо за прочтение, это важно для меня ❤️
#javascript #web #react #theory
Фронтендеры как будто не могут договориться как им хочется писать стили 🙂. Вариантов очень много, разнообразных препроцессоров и инструментов в виде библиотек стилей, CSS фреймворков…
Вообще, CSS-in-JS — это некоторый подход, в котором мы отказываемся от массового использования стандартных CSS файлов и пишем стили внутри JS. Для реализации этого концепта есть несчётное количество библиотек, но для React основной я бы назвал
styled-components
. Лично я вижу повальное число проектов, в которых используется эта библиотека, да и сам использовал её в достаточно часто.Причина проста: это очень удобно, по нескольким причинам.
1. CSS-in-JS позволяет генерировать стили динамически для одного класса. Стандартный CSS так не может, мы должны изменять стили только добавлением дополнительного класса, модификатора и т.д.
2. Дополнительная мета-информация при разработке переезжает из
className
в название самого тега. Если мы хотим как-то влиять на внешний вид нашего приложения, то классы мы будем записывать в переменные, соответственно прочитать их быстро не получится. В общем, сложно. Стилизованные компоненты же несут информацию о том, зачем они нужны, сразу из названия, и этой информации куда больше, чем просто div
, aside
, ul
...3. Упрощённая файловая структура. Формочки можно клепать ещё проще и быстрее, не переключаясь между файлами.
Возможно и звучит круто, но за всё это приходится платить достаточно высокую цену:
1. Стили создаются в рантайме и блокируют выполнение остального JavaScript на странице. Это приводит к проблемам с производительность, особенно для перегруженных систем. Всё это удобство в разработке приведет к тому, что пользователь будет плеваться от того, какое медленное приложение вы сделали.
Использование нативного CSS для браузера куда понятнее и быстрее, JS бандл становится меньше и грузится также быстрее, а стили подгружаются параллельно вашему коду.
В результате-то что? На мой вкус, CSS-in-JS — это и правда очень удобно. Но я полностью отказался от этого подхода в своих проектах, потому что не готов платить производительностью за все плюсы, что описал выше.
Если вы хотите писать стили быстро и качественно, то я действительно рекомендую обратить большее внимание на обычные модульные стили на каком-то препроцессоре или же вообще на Tailwind CSS. От последнего я, кстати, невероятно долго плевался, ну а потом как обычно: отрицание, гнев, торг, депрессия, влюбился… Точно рекомендую посмотреть, если ещё не пробовали)
Спасибо за прочтение, это важно для меня ❤️
#javascript #web #react #theory
Страшные рефы
Есть код:
Как сделал бы я:
Цитата из доки реакта: “Не вызывайте хуки внутри циклов, условных операторов или вложенных функций. Вместо этого всегда используйте хуки только внутри React-функций, до возврата какого-либо значения из них.”. Если это правило не соблюдать, то можно самых странных ошибок огрести.
Подробнее в официальном руководстве
@prog_way_blog — #react #review
Есть код:
const items = [1, 2, 3, 4];
const itemRefs: React.RefObject<HTMLDivElement>[] = items.map(() =>
useRef(null),
);
// и далее в вёрстке
ref={itemRefs[index]}
Как сделал бы я:
// вынести из компонента
const items = [1, 2, 3, 4];
// внутри компонента
const itemRefs = useRef([])
// и внутри вёрстки
// index берется из .map, так как элементы на
// страницу вставляются из списка
ref={element = inputRef.current[index] = element}
Цитата из доки реакта: “Не вызывайте хуки внутри циклов, условных операторов или вложенных функций. Вместо этого всегда используйте хуки только внутри React-функций, до возврата какого-либо значения из них.”. Если это правило не соблюдать, то можно самых странных ошибок огрести.
Подробнее в официальном руководстве
@prog_way_blog — #react #review
Зачем нужен useCallback
Очень распространенная ошибка, которая говорит о том, что мало кто понимает что такое
Важный вопрос, будет ли ререндерится
И ответ тут очевиден —конечно же да! Не смотря на то, что функцию мы мемоизировали и ссылка на саму функцию у нас не изменилась благодаря
Чтобы получить ожидаемое поведение, необходимо сделать очень важную вещь, а именно — мемоизировать и сам дочерний компонент:
Вот только так и только тогда мы перестанем ререндерить дочерние компоненты, так как пропсы не изменились. При ревью я заметил много случаев, когда useCallback использовать просто не нужно было, но он был.
А ещё много таких было кейсов:
Тут смысл
Пример из доки реакта
@prog_way_blog — #react #review
Очень распространенная ошибка, которая говорит о том, что мало кто понимает что такое
useCallback
и зачем он нужен.Важный вопрос, будет ли ререндерится
Component
при ререндере родителя?const Parent = () => {
const foo = useCallback(() => {
}, [])
return <Component foo={foo} />
}
const Component = (props) => { ... }
И ответ тут очевиден —
useCallback
, мы всё равно перерендерим Component
, поскольку рендерится родитель. Чтобы получить ожидаемое поведение, необходимо сделать очень важную вещь, а именно — мемоизировать и сам дочерний компонент:
const Component = memo((props) => { ... })
Вот только так и только тогда мы перестанем ререндерить дочерние компоненты, так как пропсы не изменились. При ревью я заметил много случаев, когда useCallback использовать просто не нужно было, но он был.
А ещё много таких было кейсов:
const Component = () => {
const foo = useCallback(() => {
}, [])
return <button onClick={() => foo()} />
}
Тут смысл
useCallback
теряется вдвойне, так как в пропсах мы всё равно пересоздаём функцию на каждый рендер вот тут: onClick={() => foo()}
Пример из доки реакта
@prog_way_blog — #react #review
Как сохранять состояние в URL
В одном из прошлых постов я рассматривал требования к стажировке в Авито. Одним из требований к тестовому было кешировать значения в URL, в этом посте рассмотрим это более подробно и сделаем самую простую реализацию такого функционала.
Представим, что у нас есть строковый инпут для имени пользователя, его состояние в URL может выглядеть следующим образом:
Соответственно, нам нужен инструмент, который позволит управлять этим состоянием. Как бы хотелось это видеть? Лично мне — ровно так же, как работает и обычный
Первым аргументом будем указывать ключ в URL, а вторым — изначальное состояние. Далее рассмотрим внутреннюю имплементацию хука и начнём с его интерфейса, тут всё достаточно просто:
Реализуем наш собственный хук на базе
Ну а всё что нужно далее — реагировать на изменение состояния и обновлять URL в соответствии с ним. Если в инпуте вдруг окажется пустая строка, то мы просто удалим наше состояние из Query параметров
Да и всё. Всё работает.
Вот весь код, который, конечно же, не идеальный. Смысл поста — отразить основную суть.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #typescript #web #react
В одном из прошлых постов я рассматривал требования к стажировке в Авито. Одним из требований к тестовому было кешировать значения в URL, в этом посте рассмотрим это более подробно и сделаем самую простую реализацию такого функционала.
Представим, что у нас есть строковый инпут для имени пользователя, его состояние в URL может выглядеть следующим образом:
www.site.com/?name=progway
Соответственно, нам нужен инструмент, который позволит управлять этим состоянием. Как бы хотелось это видеть? Лично мне — ровно так же, как работает и обычный
useState
. Тогда от этого и будем отталкиваться:const [name, setName] = useQueryState("name");
const [surname, setSurname] = useQueryState("surname", "Putnov");
Первым аргументом будем указывать ключ в URL, а вторым — изначальное состояние. Далее рассмотрим внутреннюю имплементацию хука и начнём с его интерфейса, тут всё достаточно просто:
type QueryValue = string | undefined;
function useQueryState<I extends QueryValue>(
queryKey: string,
defaultValue?: I,
) {
// тело хука
}
Реализуем наш собственный хук на базе
useSearchParams
из react-router-dom
для удобного доступа к состоянию URL-a. Если вы используете другой роутинг, можно использовать аналогичный механизм, который подойдёт именно в вашем проекте. Мы же будем его использовать для изменения URL-a и восстановления состояния из URL-a при маунте компонента. Если в URL-е уже есть состояние, мы будем использовать его. Если нет, будем использовать defaultValue
:const [searchParams, setSearchParams] = useSearchParams();
const [state, setState] = useState<QueryValue>(() => {
const targetValue = searchParams.get(queryKey);
if (targetValue !== null) {
return targetValue;
}
return defaultValue;
});
Ну а всё что нужно далее — реагировать на изменение состояния и обновлять URL в соответствии с ним. Если в инпуте вдруг окажется пустая строка, то мы просто удалим наше состояние из Query параметров
useLayoutEffect(() => {
setSearchParams((prev) => {
if (state) {
prev.set(queryKey, state);
} else {
prev.delete(queryKey);
}
return prev;
});
}, [state, queryKey, setSearchParams]);
Да и всё. Всё работает.
Вот весь код, который, конечно же, не идеальный. Смысл поста — отразить основную суть.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #typescript #web #react
Че там в React 19
У меня сейчас, к сожалению или к счастью, нет времени полностью посмотреть React Conf, которая длится аж 4 часа, что имхо очень много.
Я пролистал конфу и нашёл пару интересных моментов, которыми хочу поделиться тут.
Как я понял, React Compiler — это что-то, что стоит сравнивать скорее с компилятором TypeScript. Также один из спикеров сравнивает его с компиляторами типа WebAssembly и Hermes, который сейчас используется в React Native. По сути, всё, что он делает — разбирает весь ваш код и представляет его в виде полностью контролируемого графа. Сам по себе компилятор содержит очень много оптимизаций, типа автоматического удаления неиспользуемого кода, распространения констант и ещё куча умных слов. Все эти техники оптимизации не новы, но спикеры подмечают, что, конечно же, подсосали всё из Rust и C++, что не удивительно.
Цель такого компилятора — дополнительно оптимизировать весь наш код без видимых изменений для разработчика, тем самым улучшить и DX, и UX.
Что наиболее интересно — компилятор приносит нам такое интересное понятие как Computation Graph. Как я понимаю, это понятие мы ещё не раз услышим в будущем.
Computation Graph — граф, который отображает вычислительные зависимости между сущностями в коде. Показывает то, каким образом данные влияют на другие данные и на вёрстку в целом. Что-то типа
Тут обращаем внимание на скрины. Со 2 по 6 мы видим то, что такое Computation Graph и как он получается из нашего кода. На 7 скрине мы видим как это работает. Из полученного графа мы можем узнать минимально нужный перечень сущностей для обновления, то есть что конкретно мы хотим обновить, при этом не затрагивая остальные несвязанные ветви графа.
Во что конкретно компилятор собирает это — я пока не досмотрел. Но даже эта ограниченная информация — очень интересно)
@prog_way_blog — чат — #theory #react #news
У меня сейчас, к сожалению или к счастью, нет времени полностью посмотреть React Conf, которая длится аж 4 часа, что имхо очень много.
Я пролистал конфу и нашёл пару интересных моментов, которыми хочу поделиться тут.
Как я понял, React Compiler — это что-то, что стоит сравнивать скорее с компилятором TypeScript. Также один из спикеров сравнивает его с компиляторами типа WebAssembly и Hermes, который сейчас используется в React Native. По сути, всё, что он делает — разбирает весь ваш код и представляет его в виде полностью контролируемого графа. Сам по себе компилятор содержит очень много оптимизаций, типа автоматического удаления неиспользуемого кода, распространения констант и ещё куча умных слов. Все эти техники оптимизации не новы, но спикеры подмечают, что, конечно же, подсосали всё из Rust и C++, что не удивительно.
Цель такого компилятора — дополнительно оптимизировать весь наш код без видимых изменений для разработчика, тем самым улучшить и DX, и UX.
Что наиболее интересно — компилятор приносит нам такое интересное понятие как Computation Graph. Как я понимаю, это понятие мы ещё не раз услышим в будущем.
Computation Graph — граф, который отображает вычислительные зависимости между сущностями в коде. Показывает то, каким образом данные влияют на другие данные и на вёрстку в целом. Что-то типа
useMemo
и других хуков, когда мы напрямую указывали реакту, изменение чего конкретно нужно отслеживать и что конкретно нужно пересчитать. Теперь этим полностью занимается компилятор. Тут обращаем внимание на скрины. Со 2 по 6 мы видим то, что такое Computation Graph и как он получается из нашего кода. На 7 скрине мы видим как это работает. Из полученного графа мы можем узнать минимально нужный перечень сущностей для обновления, то есть что конкретно мы хотим обновить, при этом не затрагивая остальные несвязанные ветви графа.
Во что конкретно компилятор собирает это — я пока не досмотрел. Но даже эта ограниченная информация — очень интересно)
@prog_way_blog — чат — #theory #react #news
Как менять состояние вкладки по интервалу
Полезная фича для демонстрации, например, уведомлений, которая может пригодиться на очень большом количестве сайтов
Для реализации нам необходимо создать состояния, между которыми мы хотим перемещаться:
Далее необходимо завести состояние, которое будет определять на каком этапе из списка состояний мы сейчас находимся. Это состояние можно будет менять через обычный интервал:
И в зависимости от текущего состояния изменяем параметры вкладки:
Очевидно, что в таком исполнении решение выглядит не очень красиво. Можно создать кастомный хук и вынести всю логику туда, например, или воспользоваться нативными контекстами. В общем, сделать из этого решения либу, которую можно будет легко перенести из проекта в проект
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #web #theory #javascript #react
Полезная фича для демонстрации, например, уведомлений, которая может пригодиться на очень большом количестве сайтов
Для реализации нам необходимо создать состояния, между которыми мы хотим перемещаться:
const states = [
{ title: "Мессенджер", icon: Favicon1 },
{ title: "Новое сообщение", icon: Favicon2 },
]
Далее необходимо завести состояние, которое будет определять на каком этапе из списка состояний мы сейчас находимся. Это состояние можно будет менять через обычный интервал:
const [stateIndex, setStateIndex] = useState(0);
// раз в секунду переходим на следующее состояние
useEffect(() => {
const intervalId = setInterval(() => {
setStateIndex((prevIndex) => (prevIndex + 1) % states.length);
}, 1000);
return () => clearInterval(intervalId);
}, []);
И в зависимости от текущего состояния изменяем параметры вкладки:
useEffect(() => {
const link = document.querySelector("link[rel~='icon']");
const title = document.querySelector("head title");
if (link) {
link.href = states[stateIndex].icon;
title.textContent = states[stateIndex].title;
}
}, [stateIndex]);
Очевидно, что в таком исполнении решение выглядит не очень красиво. Можно создать кастомный хук и вынести всю логику туда, например, или воспользоваться нативными контекстами. В общем, сделать из этого решения либу, которую можно будет легко перенести из проекта в проект
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #web #theory #javascript #react
Флоу рендеринга компонента в React
Небольшая шпаргалка, которая содержит в себе очередь вызова эффектов при маунте и апдейте компонента.
➡️ При маунте порядок следующий:
1. Рендер на основе изначальных значений состояний
2.
3. Создание DOM
4. Прикрепление ссылок на ноды (ref)
5.
6.
➡️ При апдейте компонента:
1. Рендер на основе новых значений состояний
2. Обновление DOM
3.
4. Прикрепление ссылок на ноды (ref)
5.
6.
📎 Решил вынести её в канал, потому что сам прям недавно сталкивался с этим на рабочем проекте и подумал, что это тоже кому-то может быть полезно
Ну и не реклама, а реально рекомендация — на эту тему хочу поделиться видео Аюба Бегимкулова о нестандартном применении useInsertionEffect. Там он более подробно рассказывает почему порядок именно такой и в целом чуть более подробно раскрывает тему рендера с примерами в коде
Спасибо за прочтение, это важно для меня❤️
@prog_way_blog — чат — #web #theory #react
Небольшая шпаргалка, которая содержит в себе очередь вызова эффектов при маунте и апдейте компонента.
1. Рендер на основе изначальных значений состояний
2.
useInsertionEffect
3. Создание DOM
4. Прикрепление ссылок на ноды (ref)
5.
useLayoutEffect
6.
useEffect
1. Рендер на основе новых значений состояний
2. Обновление DOM
3.
useInsertionEffect
4. Прикрепление ссылок на ноды (ref)
5.
useLayoutEffect
6.
useEffect
Ну и не реклама, а реально рекомендация — на эту тему хочу поделиться видео Аюба Бегимкулова о нестандартном применении useInsertionEffect. Там он более подробно рассказывает почему порядок именно такой и в целом чуть более подробно раскрывает тему рендера с примерами в коде
Спасибо за прочтение, это важно для меня
@prog_way_blog — чат — #web #theory #react
Please open Telegram to view this post
VIEW IN TELEGRAM