Chulakov Dev – Telegram
Chulakov Dev
1.16K subscribers
139 photos
5 videos
204 links
Канал команды разработки Студии Олега Чулакова.

Советы по Frontend- и Backend-разработке web-сервисов, мобильных приложений, статьи и презентации от наших разработчиков, анонсы проектов и многое другое.

Обсудить проект @YuraAndreev
Download Telegram
Всем привет!

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

Приятного чтения.
🔥15👍3😱2
Всем привет!

Как правильно ответить на вопрос «Что такое чистая функция?», если различные источники дают разные трактовки? Кажется, мы нашли лучшее определение этому понятию. Следите за ходом мысли.

Функция должна иметь только одну точку входа и только одну точку выхода из нее. Давайте назовем их ординарными, так как эти точки работают максимально ожидаемо. Следовательно, максимальная ожидаемая точка входа — это аргументы функции, а точка выхода — оператор return.

Почему только по одной точке на вход и выход?

Абсолютно любой другой вход в функцию — это использование внешних переменных, функций и т.д. — побочное действие.
Абсолютно любой другой выход из функции — присвоение значений внешним переменным, операции ввода/вывода, HTTP-запросы — побочное действие.

В итоге мы имеем следующее определение:

Чистая функция — это функция, которая имеет только одну ординарную точку входа (ее аргументы) и одну ординарную точку выхода (оператор return).

+1 понятие в вашу копилку.

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍21
Привет, друзья!

На прошлой неделе многие из вас справились с задачей по Event Loop 💪🏼 Сможете ли вы правильно ответить на сегодняшний вопрос?

Он ниже вместе с вариантами ответа👇🏻 Выбирайте.
👍102🤔1
Всем привет!

Давайте разберем вчерашний вопрос «Какой функциональный объект в JS можно назвать функтором?».

Правильный ответ — вариант № 2: объект, реализующий метод map.

Объясняем, почему.

Функтор в JS — это объект, который получает некие значения, преобразует их с помощью внутренней чистой функции и возвращает результат с аналогичной структурой данных. Среди наших вариантов ответа такой метод только один, и это — map.

Теперь давайте рассмотрим другие варианты.

Sort — изменяет входной массив, т.е. он не является чистой функцией.

Reduce — также может вернуть аналогичную структуру, но это не гарантированно, т.к. он более универсален.

Next — метод для передачи данных следующей итерации, и он не используется для преобразования.

Если остались еще вопросы, задавайте.

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥41🤔1
Привет, друзья!

🤔 Интересно, вы когда-нибудь слышали о методе requestIdleCallback?

Сегодня поговорим о нем.

⚫️Метод requestIdleCallback очень редко используется, но в некоторых моментах он может значительно оптимизировать ваш код. Его суть заключается в следующем: метод принимает в качестве первого аргумента колбэк, который ставит в очередь Task Queue, и этот колбэк выполняется, когда браузер находится в режиме простоя.

Другими словами, когда браузеру «нечего делать», он может взять функцию, переданную через requestIdleCallback, и выполнить ее, тем самым не мешая выполнению других задач, когда это необходимо.

⚫️Вторым аргументом он принимает дополнительные параметры, но пока реализован только один — timeout. В нем вы можете указать максимальное время (в миллисекундах), которое потребуется колбэку на выполнение. Если он не уложится в отведенное вами время, выполнение колбэка прервется.

Этот метод пока не поддерживается в Safari, но мы надеемся, что специалисты из Apple вскоре реализуют такую классную возможность.

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍204🔥4
Всем привет!

На рынке веб-разработки существует множество CMS с готовой административной панелью и набором базовых функций, таких как WordPress, 1C-Bitrix, Joomla и другие.

Но иногда требуется реализовать проект с индивидуальным дизайном и функционалом. В таком случае на помощь приходят Headless CMS. Они содержат серверную часть, API и базу данных, которая используется для хранения контента.

Одной из популярных Headless CMS с открытым исходным кодом является Strapi. Сегодня мы соберем свой образ для использования в проектах.

👉🏻 Читать пошаговую инструкцию

@chulakov_dev
🔥22👍43
Всем привет!

При разработке frontend-приложений важно учитывать ситуации, когда данные от backend еще не доступны. React Query и его хук useQuery предлагают инструменты для управления этим процессом.

Один из ключевых параметров, на который следует обратить внимание, — isLoading. Он показывает, выполняется ли запрос данных. Если обратиться к data без проверки isLoading, это может вызвать ошибку, так как данные могут быть еще недоступны.

const { isLoading, error, data } = useQuery('myData', fetchData);

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

function MyComponent() {
const { isLoading, error, data } = useQuery('myData', fetchData);

if (isLoading) return 'Загрузка...';
if (error) return `Произошла ошибка: ${error.message}`;

return (
<div>
<h1>{data.noscript}</h1>
<p>{data.denoscription}</p>
</div>
);
}

Здесь, если isLoading = true, компонент просто отображает сообщение «Загрузка...», а использование данных начинается только после их успешной загрузки.

Вы можете думать, что проверка isLoading не всегда необходима и в некоторых случаях можно использовать опциональную цепочку (optional chaining). Однако это может быть опасно. Если данные еще не получены, а мы пытаемся передать их в компонент, ожидающий конкретные данные, это может привести к ошибке. Вот пример:

function MyOtherComponent({ noscript, denoscription }) {
return (
<div>
<h1>{noscript}</h1>
<p>{denoscription}</p>
</div>
);
}

function MyComponent() {
const { data } = useQuery('myData', fetchData);

return (
<MyOtherComponent noscript={data?.noscript} denoscription={data?.denoscription} />
);
}

В этом случае, если данные еще не получены, опциональная цепочка вернет undefined для data?.noscript и data?.denoscription, что может вызвать ошибку в MyOtherComponent.

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

@chulakov_dev
🔥17👍53🤔2
Привет!

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

Итак, внимание, вопрос! 👇🏻
👍10🔥4🤔3
Как добавить изменения в последний коммит, не создавая новый и не изменяя его описания?
Anonymous Quiz
5%
git commit --current-message
3%
git commit -t
69%
git commit --amend --no-edit
23%
git commit --amend -m false
🔥108👍6🤯1
Всем привет!

Многие из вас наверняка знают про метод stopPropagation. Он связан с таким понятием, как event bubbling, а сам он останавливает действие всплытия/погружения наступившего события.

Но (для нас это не было неожиданностью) почти никто не знает о его брате — методе stopImmediatePropagation. Он используется намного реже stopPropagation, но знать о нем нужно и важно.

Метод stopImmediatePropagation останавливает все всплытия/погружения всех событий на определенном HTML-элементе. Допустим, если один элемент регистрирует у себя несколько событий, например от нескольких дочерних элементов, и они все начинают всплывать, то метод stopPropagation остановит только один из них, а stopImmediatePropagation — все.

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

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥54
Всем привет!

Сегодня хотим рассказать интересный факт о скорости разных циклов. Вы знали, что forEach работает быстрее обычного for в 2–4 раза?

Вот доказательство:
const arr = new Array(10000).fill(0).map((_, i) => i);

function forFn() {
let res;

for (let i = 0; i < arr; i++) res = arr[i];
}

function forEachFn() {
let res;

arr.forEach(item => res = item);
}

function calculateLoopTime(callback) {
const time = performance.now();
callback();

console.log(performance.now() - time);
}

calculateLoopTime(forFn); // от 0.3s до 0.7s
calculateLoopTime(forEachFn); // от 0 до 0.3s

Почему так происходит: for для работы своих итераций требуется каждый раз создавать переменную с текущим индексом, в то время как forEach обращается к элементу массива по его внутреннему индексу, а это гораздо быстрее.

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

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥73
Привет, друзья!

Сегодня мы коснемся важной темы: как правильно использовать key при рендеринге списков в React.

🔑 Key — это специальный атрибут для эффективного сопоставления элементов при изменении списка (и не только, но сейчас не об этом). Он критически важен для оптимальной производительности.

Проще всего в качестве ключа указать индекс элемента в массиве, однако подобный подход равносилен полному отсутствию ключа. Иногда это не приводит к проблемам, например, если ваш функционал предусматривает только добавление нового элемента в конец или ваш список абсолютно статичен.

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

Как же решить эту проблему и обезопасить себя?

Используйте уникальные ID в качестве ключей. Если данные приходят с бэкенда, они, вероятно, уже имеют ID. На клиентской стороне вы можете указать сами уникальные идентификаторы или использовать библиотеку Nanoid для генерации, но делать это нужно не в момент рендера, а при определении массива. Кстати, по этой же причине и не рекомендуется применять метод Date.now().

Может показаться, что использовать Date.now() в качестве уникального ID — это быстрый и простой способ. Но здесь скрыта уязвимость: если вы попытаетесь создать два элемента одновременно, получите два одинаковых ID. Поэтому вместо поиска быстрых решений лучше довериться проверенным инструментам и способам.

😕 Вы могли заметить, что мы не упомянули хук useId. Дело в том, что такие идентификаторы будут уникальны только в рамках компонента, а нам нужны ID, которые уникальны глобально в рамках всего приложения.

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

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥173👍1
Друзья, привет!

Давайте устроим разминку для мозгов! На картинке задача, которую мы предлагаем вам решить.

Ниже выбирайте свой вариант ответа👇🏻
👍8🔥51
Что будет выведено в консоль?
Anonymous Quiz
38%
Hi!
40%
Hello!
8%
undefined
14%
Будет ошибка
👍10🔥7😢2
Привет!

В системе типов TypeScript есть группа, которая называется гомоморфной, т.е. типы, которые изменяют функциональность, сохраняя первоначальные свойства применяемой сущности. В этой группе есть четыре типа: Readonly, Partial, Required, Pick.

Readonly
— добавляет каждому свойству/методу объекта модификатор readonly, т.е. делает их доступными только для чтения.

type User = {
name?: string;
}

type ReadonlyUser = Readonly<User> // { readonly name?: string; }

const user: ReadonlyUser = {
name: 'Jack'
}

// Cannot assign to 'name' because it is a read-only property.
user.name = 'John'

Обратите внимание на знак вопроса у свойства name. Мы намеренно сделали его необязательным, но Readonly оставит его таковым, так как, являясь гомоморфным, он не изменяет остальные модификаторы.

Partial добавляет всем свойствам/методам модификатор ?, делая их необязательными.

type User = {
readonly name: string;
age: number;
};

type OptionalUser = Partial<User>; // { readonly name?: string; age?: number; }

const user: OptionalUser = {}; // Ok!

Required противоположен Partial. Он превращает члены объекта в обязательные, удаляя модификатор ?.

type User = {
readonly name?: string;
age?: number;
};

type RequiredUser = Required<User>; // { readonly name: string; age: number; }

/**
* Type '{}' is missing the following properties
* from type 'Required<User>': name, age
*/
const user: RequiredUser = {}

И последний — Pick. Фильтрует объектный тип по свойствам/методам и формирует из него новый тип. Если вы знаете, как работает тип Omit, то это противоположная ему процедура. Первый дженерик принимает в себя фильтруемый тип, а второй — перечисление свойств/методов, которые требуется отфильтровать (перечисляются через оператор | ):

type User = {
readonly name: string;
age: number;
height: number;
};

// { readonly name: string; age: number; }
type PickUser = Pick<User, 'name' | 'age'>;

const user: PickUser = {
name: 'Jack'
}

// Cannot assign to 'name' because it is a read-only property.
user.name = 'John'
👍16🔥52
Всем привет!

Недавно у нас был пост с инструкцией, как создать свой образ Strapi. Сегодня мы расскажем, как настроить окружение для его дальнейшего использования в Docker.

👉🏻 Читать инструкцию

@chulakov_dev
🔥12👍54
Друзья, привет!

➡️ Сегодня поговорим про замечательную функцию от Next.js — Incremental Static Regeneration (ISR) — и про то, как ревалидировать данные на уровне страницы по таймеру. Тема актуальна для всех, кто использует версию Next.js >= 12.4.

ISR — это функциональность, которая позволяет динамически обновлять статические страницы после сборки проекта, не пересобирая весь сайт, что очень полезно при частом обновлении контента (новости, цены в каталоге и т.д.).

↪️ По сути, это комбинация из лучшего, что есть у SSR/RSC и SSG, которая работает следующим образом:
— при первом запросе к странице отдается кешированная версия из сборки;
— затем в фоновом режиме запускается повторная генерация страницы через вызов getStaticProps;
— если генерация прошла успешно, обновленная версия попадает в кеш;
— при ошибке продолжит отдаваться предыдущая версия из кеша;
— так достигается отказоустойчивость;
— кеширование происходит локально на сервере, на Vercel кеш глобальный и автоматически распределяется (об этом сегодня не будем говорить).

Управлять ISR можно так:
— частоту обновления задать через revalidate в секундах в getStaticProps;
— принудительно очистить кеш через API-метод revalidate;
— On-demand revalidation при обновлении данных.

// пример использования

export const getStaticProps = async () => {

return {
props,
revalidate: 10, // ревалидировать каждые 10 секунд
}


}


// On-demand
await res.revalidate('/some-page')

Таким образом, ISR позволяет оптимально сочетать скорость статической генерации и гибкость обновления данных. Рекомендуем для сайтов с часто меняющимся контентом!

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥174👍4
Всем привет!

В новой статье на Хабре мы разобрали основные особенности языка Kotlin. Рассмотрели такие важные аспекты, как безопасность работы с null-значениями, гибкость типизации с помощью Generics, возможности расширения функциональности с помощью extension-функций, inline-функции и многое другое.

А еще поделились ссылками на полезные материалы, которые пригодятся в изучении Kotlin.

➡️Читайте и подписывайтесь на наш блог.

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍43
Мы все долго ждали этого момента — выхода нового большого интервью Олега Чулакова.

Олег поделился первыми успехами Студии на международном рынке и планами на будущее. Рассказал про идеологию Студии, которая выделяет ее на фоне других агентств и почему все копируют Студию. Обсудили бизнес в Дубае и России, найм сотрудников и многое другое. Получилось интересно, честно и с юмором.

Кто еще не смотрел, держите ссылку на интервью. Приятного просмотра.

@chulakov_dev
🔥133🐳32
Всем привет!

Готовы проверить свои знания по команде git push?

Ниже вопрос и варианты ответов👇🏻
❤‍🔥7🔥1