cherkashin.dev – Telegram
cherkashin.dev
2.08K subscribers
188 photos
13 videos
244 links
Александр Черкашин. Бойскаут, Борец с перфекционизмом.

Для связи 👉 @cherkalexander

Фулстек разработчик в decisions.com. Работаю со стеком TypeScript, React, C#

Пишу о программировании и не только.


Блог: https://cherkashin.dev
Download Telegram
Сегодня увидел, что Хабр советует прочитать мою старую статью с советами о выгорании, поэтому я решил напомнить о ней. Как раз подходит, чтобы отвлечься от работы, расслабиться и почитать вечером в пятницу.

https://habr.com/ru/post/598517/

#fridayreading #burnout
👍11
🚀 React — Compound Components

Как-то я уже упоминал паттерн Compound Components (Составные компоненты) для React, теперь остановимся на нём немного подробнее.

ℹ️ Compound components — это подход позволяет объединить несколько компонентов в единую сущность, которая неявно имеет общее состояние. Эти компоненты тесно взаимодействуют друг с другом и работают как единое целое, представляя собой полноценный UI компонент.

🔍 Основные характеристики:
- Используется React контекст, чтобы управлять состоянием
- Должен быть главный компонент, в котором хранится состояние и объявляется React контекст
- Все дочерние компоненты используют состояние через React контекст

ℹ️ Он состоит из 2 простых подходов React:
1. Композиция компонентов
2. Паттерн “Провайдер” — использование контекста React

📝 Вначале рассмотрим подходы по отдельности

1️⃣ Что такое композиция?

Вместо вот этого

<Tile count={money} noscript="Стоимость" icon={<MoneyIcon/>}/>


Мы пишем вот так

<Tile>
<Title>{noscript}</Title>
<Number>{count}</Number>
<Icon>{icon}</Icon>
</Tile>


Когда это может понадобиться? Например, когда у нас креативный дизайнер и нам нужно угодить ему:

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

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

2️⃣ Паттерн “Провайде
р”

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

🔄 Если объединить два этих подхода, то сможем реализовать паттерн Compound Components. Как пример, можно использовать компонент табов из библиотеки material-ui.

function MyTabs() {
return (
<TabContext value={value}>
<TabList onChange={handleChange}>
<Tab label="Item One" value="1" />
<Tab label="Item Two" value="2" />
<Tab label="Item Three" value="3" />
</TabList>Ï
<TabPanel value="1">Item One</TabPanel>
<TabPanel value="2">Item Two</TabPanel>
<TabPanel value="3">Item Three</TabPanel>
</TabContext>
);
}


1. TabContext — главный компонент, в котором хранится состояние и объявляется React контекст
2. Tab и TabPanel получают текущее значение активного таба неявно через React контекст. Явно значение не передаётся в каждый компонент.
3. onChange объявлен только на компоненте TabList, компоненты Tab неявно получают его из контекста.

Ещё по теме:

- Александр Дунай (Альфа-Банк) — Улучшаем качество кода React-приложения с помощью Compound Components
- JavaScript Patterns — Provider Patter
- JavaScript Pattern — Compound Pattern

#react #frontend #architecture #patterns
👍10
🔮 Абстракция

Когда говорят про ООП, часто забывают о двух вещах:

- Это не только инкапсуляция, наследование и полиморфизм, но ещё и абстракция
- Инкапсуляция, наследование и полиморфизм не прибиты гвоздями к ООП, особенно инкапсуляция и полиморфизм. Но об этом не сегодня.

Сегодня советую к просмотру видео: Абстракция, уровни абстракции.

ℹ️ Основные моменты:

- Абстракция — отвлечение от несущественных сторон, свойств, связей объекта с целью выделения их существенных, закономерных признаков. Иными словами, мы выделяем существенные свойства для нашей конкретной задачи, и не обращаем на несущественные.
- Абстрация = Интерфейс + Инкапсуляция
- Интерфейс — выделяет существенное
- Инкапсуляция — скрывает несущественное
- Абстрагирование нужно для управления сложностью кода, чтобы всё было надёжно, эффективно, расширяемо и поддерживаемо.

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

- Если нам важно вычислять его площадь и периметр, то мы говорим, что квадрат — это геометрическая фигура (абстрагируемся). Иначе говоря квадрат реализует интерфейс IGeometricShape.
- Если нам важно, чтобы квадрат мог быть сохранён в файл, то мы говорим, что квадрат — сериализуемый, например, в JSON объект, который затем можно записать в файл. Иначе говоря квадрат реализует интерфейс ISerializable.
- Аналогично, если нам важно уметь рисовать квадрат на экране, он должен реализовывать интерфейс IDrawable.
- Ну и где-то у нас есть методы, которые работают с абстракциями IGeometricShape, ISerializable и IDrawable. Таким образом методы абстрагированы от конкретных реализаций, что увеличивает переиспользуемость кода.

Ну и немного от себя, абстракция — фундаментальное понятие.
- Без абстракции не будет полиморфизма
- Без полиморфизма не будет Dependency Injection (Внедрение зависимостей)

#fridayreading #essential #oop
👍9🔥2
Яндекс.Музыка уже давно поменяла логотип, поэтому пришло время обновить его и в расширении для VS Code.

P.S. За иконки спасибо автору Мастерской Программиста 👍
👍9👎1
​​Уровни абстракции

Уровни абстракции — одна из самых важных и одновременно самых сложных концепций, понимание которой ведёт к написанию качественного кода.

Методы и функции — один из самых простых примеров, на основе которых можно рассмотреть концепцию уровней абстракции.

ℹ️ Когда мы описываем функцию, то все методы, которые мы вызываем внутри должны находиться на один уровень абстракции ниже. В конце концов, функции пишутся прежде всего для разложения более крупной концепции (иначе говоря, имени функции) на последовательность действий на следующем уровне абстракции.

Как понять, что метод написан на разных уровнях абстракции

- Когда мы смешиваем уровни абстракции, то функция обрастает большим количеством второстепенных подробностей — деталями с более низкого уровня абстракции
- Если читать код функции, вы найдёте одновременно действия, которые будут отвечать на вопросы “что?” и “как?”:
- “что?” — более высокий уровень абстракции, тут функция описывает, что мы делаем.
- “как?” — тут будет описано, “как” мы что-то делаем, а чтобы понять что именно, нужно будет напрячь извилины и подумать. И если мы заменим это “как” на функцию, имя которой будет отвечать на вопрос “что”, то всё станет на свои места и будет на одном уровне абстракции.

⚠️ Не окрепшим умам главное понять, что метод написанный на “одном уровне абстракции” это то, к чему нужно стремиться, но главное не переусердствовать, ведь не всегда так просто провести грань между уровнями абстракции.

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

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

Пример от Дядюшки Боба найдёте в комментариях, из него должно стать понятней, что имелось ввиду при описании “что?” и “как?”

#architecture #cleancode #abstraction
🔥3👍1
Forwarded from mefody.dev
Подсветка кода на странице при помощи Custom Highlight API

Если вы встраивали показ кода на страницы своих сервисов, то скорее всего приходилось прикручивать и подсветку этого кода, чтобы были красивые цвета у разных наборов токенов, как в любимом IDE. Для этого есть много готовых библиотек, так что сложности особой нет. Но все эти библиотеки сейчас создают большое количество span с набором классов для стилизации.

Брамус показывает, как можно применять современный Custom Highlight API, чтобы не создавать span для стилизации в принципе. Это такая апишка, которая уже работает в Chrome 105 и Safari 17.2. И она позволяет при помощи JavaScript разбивать текстовые узлы на набор параметризированных токенов. Как это делать в JS, лучше смотреть в самой статье. Но зато в CSS всё становится сильно приятнее:


::highlight(important) {
color: red;
font-weight: bold;
}

::highlight(attr) {
color: violet;
}


Имена хайлайтов как раз задаются в JS.

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

https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/
👍3🔥1
Forwarded from Hello, IT’s Mihello
Подборка для изучения CSS в игровой форме:

1. Flexbox groggy
2. Grid garden
3. Flexbox defense
4. Flexbox zombies 🧟‍♀️
5. Knights of the Flexbox Table
6. Flex Box adventure
7. CSS Diner
8. Grid attack

Бонус:
CSS Battle
100 days of CSS
CSS Challenges
5🔥1
☁️ Облако слов

Ради интереса решил построить облако слов на основе комментариев в пул реквестах.

Нашёл пару подходящих библиотек:

- react-tagcloud — нет типов для тайпскрипта, и облако само по себе выглядит не очень красиво
- react-wordcloud — типы есть, облако выглядит неплохо, использовать легко

<ReactWordcloud
size={[1000, 500]}
words={data}
maxWords={350}
options={{ fontSizes: [10, 120] }}
callbacks={{
onWordClick: (e) => {
onClick(e.text);
},
}}
/>


#library #react
👍2🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
🆙 Кнопки в базах данных Notion

Когда-то давно я писал, как автоматически заполнять Completed Date поле в Notion.

С тех пор много воды утекло, и кажется об использовании Github Actions для этих целей можно забыть.

В Notion уже давно есть кнопки, наконец-то они появились и в базах данных.

Ещё пример

#notion #automation
👍2🔥1
Наконец-то попаду на "Я 💛 Фронтенд" в оффлайне. Трансляция тоже будет.

https://events.yandex.ru/events/ya-love-frontend-2024

#conference
🔥7👍3
👨‍💻 Phind

В комментариях к прошлому посту о Codeium мне порекомендовали попробовать Phind.

До расширения для VS Code руки ещё не дошли, а вот онлайн версией пользуюсь достаточно регулярно. Очень удобно учитывая, что он бесплатный, генерирует неплохие ответы и не нужно постоянно включать VPN, если вы находитесь в России.

Вначале не мог запомнить название, но потом понял, что phind — это find через ph и всё стало на свои места.

У Phind есть 2 режима:

1️⃣ Чат — стандартный чат, аналогичный ChatGPT

2️⃣ Поиск — phind сгенерирует ответ и покажет ссылки на использованные источники в интернете.

Также позволяет запустить сгенерированный код в Replit.

#ai
👍10🔥2
⚙️ .editorconfig

Вопрос от менти: У меня проблемы с кодировкой. В гитхабе вижу битые символы вместо русских букв. Почему и как исправить?

Ответ: Скорее всего редактор создаёт файлы в кодировке типа “Cyrillic (Windows 1251)”. Чтобы это исправить, нужно пересохранить существующие файлы в кодировке UTF-8.

А, чтобы новые файлы создавались с правильной кодировкой, в корне проекта нужно создать файл .editorconfig и указать что все файлы ([*]) должны иметь кодировку utf-8 (charset = utf-8).

[*]
charset = utf-8


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

В нём же можно настроить отступы, размер табов и прочее. Подробнее здесь.

#mentee_question #essential
🔥7
New client-side hooks coming to React 19

Статья рассказывает про новые API, которые, предположительно, будут в react 19. Пока они доступны в канареечном релизе React

В статье рассказывается про:
- use(Promise)
- use(Context)
- Возможность передавать специфичный action в form
- useFormState
- useFormStatus
- useOptimistic
- Асинхронные транзишны

Постараюсь коротко рассказать про это API

use(Promise) позволяет дождаться выполнения Promise. Выглядит как сахар для удобного ожидания промиса внутри Suspence. Также отличается от классических хуков тем, что этот можно использовать внутри циклов и условий


import { use } from 'react';

function MessageComponent({ messagePromise }) {
const message = use(messagePromise);
// ...
}


use(Context) это аналог useContext, но можно использовать внутри циклов и условных блоков

Также улучшили работу с формами. У форм есть проп action, в который теперь можно закидывать функцию - обработчик формы <form action={handleSubmit}>. Само по себе это мало что дает, но вместе с этой возможностью идут новые хуки, которые позволяют получить стейт и статус формы - useFormState и useFormStatus. Используя комбинацию этих API можно удобно работать с нативными формами.

Самой сложной API для меня оказался хук useOptimistic. Пришлось из статьи перейти в доку реакта, чтоб почитать подробнее, как это работает. Как я понял, useOptimistic позволяет врапнуть другой стейт и изменить его, пока врапнутый стейт не изменился. И это может быть полезно для оптимистичных апдейтов UI (техника, когда мы отрисовываем экран исходя из того, что асинхронное действие завершится успехом)

Я понял, что это работает вот так
function MyComponent() {
// Объявляем стейт
const [state, setState] = useState([])
// Врапуем его с помощью нового хука
// в optimisticState изначально будет лежать state
// В колбеке описываем, как обрабатывать оптимистичные изменения
const [optimisticState, addOptimistic] = useOptimistic(state, (state, newItem) => [...state, newItem])

// Предположим мы делаем запрос на did mount
useEffect(async () => {
const itemToAdd = {}
// добавляем оптимистичный апдейт
addOptimistic(itemToAdd)
// делаем запрос
const realItemToAdd = await fetch(url)
// после завершения запроса, меняем корневой стейт
// мы рендерим optimisticState, но после обновления state
// optimisticState обновиться до state
setState([...state, realItemToAdd])
}, [])

return <div> {optimisticState} </div>
}


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

Также добавили возможность делать асинхронные transitions в React. До этого было требование, чтобы транзишны были синхронными

https://marmelab.com/blog/2024/01/23/react-19-new-hooks.html

#development #javanoscript #react #react19 #reactHooks
3
⚛️ React 19 — use(Promise)

use — новый хук, который позволяет считывать данные из промиса и при этом интегрирован с Suspense и ErrorBoundary.

ℹ️ Основные моменты:

- На этот хук не распространяются правила хуков — его можно использовать внутри циклов и условных операторов.
- Если мы используем хук use(Promise), то где-то в родительском компоненте мы должны положить сам промис (не данные как мы делали раньше) в стейт (useState). Это позволяет избавиться от useEffect’а, который был нужен, чтобы запросить данные при первом рендере.
- Хук интегрирован с Suspense, поэтому пока промис не разрезолвится — будет показан fallback объявленный в ближайшем Suspense.
- Если промис зареджектился, то будет показан fallback объявленный в ближайшем ErrorBoundary

- Песочница тут
- Официальная документация тут

#frontend #react #new
5👍3
🆕Разработчикам теперь доступна GitVerse - новая российская платформа от СберТеха для работы с исходным кодом.

Сервис позволяет бесплатно создавать проекты с открытым и закрытым кодом, приглашать новых участников и общаться с единомышленниками в ИТ-сообществе.

- Встроенный AI помощник GigaCode

- Привлекайте соавторов для разработки и развития своего проекта с открытым исходным кодом

- Разрешайте вносить изменения в репозиторий, получайте запросы на слияние и объединяйте ветки

- Проверяйте и комментируйте код, объединяйте изменения

- Оптимизируйте рабочий процесс: назначайте ответственных за ревью и отслеживайте результат

- Переносите репозитории с других платформ и храните код в надежном месте

Переходим и пробуем
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🆒3🤮2
⚛️ React 19 — useOptimistic

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

Как используется

- В useOptimistic передаётся реальное состояние (cart) и функцию-reducer, для обновления оптимистичного состояния
- Компонент (Cart) использует “оптимистичное” состояние (optimisticCart) для рендера
- Перед выполнением запроса обновляется “оптимистичное” состояние
- Когда запрос завершился, нужно обновить реальное состояние
- Как только реальное состояние обновилось, оптимистичное состояние обновится автоматически, так как оно передано в useOptimistic первым параметром. ⚠️ Поэтому важно следить, чтобы приходило одно и то же состояние.
- Если запрос упал с ошибкой, нужно откатить изменения в оптимистичном состоянии.

ℹ️ Первый вопрос, которым я задался, а в чём отличие от обычного setState, путём экспериментов, вот что удалось найти:

- useOptimistic работает с формами. Работать с обычной кнопкой в Single Page Application мне не удалось, обновление происходило только после завершения запроса
- useOptimistic работает только внутри асинхронного обработчика, что логично. Если убрать async/await, обновление произойдёт только после завершения запроса
- Параметр в useState используется только для инициализации, и игнорируется в последующих рендерах. useOptimistic будет сихронизироваться со значением переданным первым параметром.

🤷‍♂️ Очень мало полезного удалось найти о useOptimistic. Во всех статьях и видео тривиальные примеры, нигде не рассказывается как обрабатывать более сложные ситуации:

- Как обновлять оптимистичное состояние, если запустить несколько запросов одновременно?
- Как использовать useOptimistic в SPA вне форм?

Поэтому пришлось создать пару ишью: раз и два. В любом случае, пока useOptimistic выглядит каким-то низкоуровневым API. Надеюсь скоро появится больше Best Practices по его применению. Если вам есть что добавить — пишите в комментах.

Ещё по теме:

- Frontend First — Ep 179 - React Deep Dive: useOptimistic
- Официальная документация по useOptimistic
- Код из примера тут

#react #frontend #new
👍5🔥3
Максимальная длина строки в V8

У меня есть небольшой пет проект, для построения различных графиков для пул реквестов, которые показывают кто кому оставляет комментарии, ставит аппрувы и прочее. Бэкенда там нет, фронт ходит в Gitlab или Gitea, выкачивает информацию за указанный период времени и рисует графики.

Чтобы не гонят лишний раз данные, я добавил возможность импорта/экспорта. Вроде всё хорошо, но вчера я решил выгрузить данные за 4 года и при экспорте словил ошибку:


JSON.stringify Uncaught RangeError: Invalid string length


Немного погуглив, нашёл, что длина строки в V8:
- 268.4 мегабайт на 32-битных платформах
- 538.8 мегабайт на 64-битных платформах (на М1 похоже такая же)

Решил проблему просто: при экспорте разбиваю мой большой массив, на несколько частей и экспортирую несколько файлов.

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


const reader = new FileReader();
reader.onload = function () {
console.log(reader.result); // result будет пустой строкой
}
reader.readAsText(file);


В Firefox такой проблемы нет, всё работает.

#browser #frontend
🔥7😱3👍2