Chulakov Dev
1.25K subscribers
109 photos
3 videos
191 links
Канал команды разработки Студии Олега Чулакова.

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

При разработке 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.title}</h1>
<p>{data.description}</p>
</div>
);
}

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

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

function MyOtherComponent({ title, description }) {
return (
<div>
<h1>{title}</h1>
<p>{description}</p>
</div>
);
}

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

return (
<MyOtherComponent title={data?.title} description={data?.description} />
);
}

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

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

@chulakov_dev
Привет!

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

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

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

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

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

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

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

Сегодня хотим рассказать интересный факт о скорости разных циклов. Вы знали, что 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
Привет, друзья!

Сегодня мы коснемся важной темы: как правильно использовать 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
Друзья, привет!

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

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

В системе типов 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'
Всем привет!

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

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

@chulakov_dev
Друзья, привет!

➡️ Сегодня поговорим про замечательную функцию от 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
Всем привет!

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

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

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

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

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

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

@chulakov_dev
Всем привет!

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

Ниже вопрос и варианты ответов👇🏻
Мы создали в локальном репозитории ссылку на другой удаленный репозиторий (git remote add github-repo ...). Как сделать в него пуш, чтобы скопировать все содержимое репозитория (ветки, теги, коммиты и т.д.)?
Anonymous Quiz
4%
git push github-repo
18%
git push --clone github-repo
54%
git push -u origin github-repo
25%
git push --mirror github-repo
Привет, друзья!

Мы собрали ТОП-5 книг по JavaScript для тех, кто только собирается погрузиться в изучение этого языка.

📔 «Изучаем программирование на JavaScript», Э. Фримен, Э. Робсон

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

📔 «Современный учебник JavaScript», И. Кантор

Самое популярное онлайн-издание по JavaScript в русском сегменте. В учебнике объясняется не только JS, но и то, как работает DOM, браузер, а также раскрываются другие важные темы. Идеальная вторая книга.

📔 «JavaScript: подробное руководство», Д. Флэнаган

Самая фундаментальная книга по JavaScript из когда-либо написанных. Осилив ее внушительный объем, можно в полной мере стать сенсеем.

📔 «Как устроен JavaScript», Д. Крокфорд

Небольшая, но емкая книга от создателя JSON. Автор понятно объясняет базовые вещи. При этом опытные senior-разработчики тоже найдут в ней что-то новое для себя.

📔 «Элегантный JavaScript», М. Хавербеке

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

А вы читали эти книги? Поделитесь своей подборкой любимых изданий.

@chulakov_dev
Please open Telegram to view this post
VIEW IN TELEGRAM
Привет!

Давайте разберем принцип работы async/await под капотом. Посмотрим, как выполняется код с обычной и асинхронной функцией — это поможет понять, почему async/await ведет себя именно так, — и разберем, почему происходит неблокирующее ожидание.

Читать про async/await

@chulakov_dev
Привет!

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

CrossConf
15.09 — Москва
Ежегодная конференция по кросс-платформенной разработке и трендам IT. После докладов желающие смогут продолжить общение с коллегами на afterparty.

Стачка
15–16.09
— Ульяновск
Десятая по счету международная IT-конференция. Темы выступлений охватят несколько разных направлений — от разработки до продаж.

FrontendConf
02–03.10
— Москва
Cамая масштабная конференция по frontend-разработке в России. Своим опытом поделятся ведущие разработчики из крупнейших IT-компаний.

Joker
09–10.10 — online
13–14.10 — Санкт-Петербург и online
Одна из старейших конференций для Java‑разработчиков. Здесь можно узнать практическую информацию об использовании Spring Boot и разобраться, как JVM работает «под капотом».

Heisenbug
10–11.10 — online
15–16.10 — Санкт-Петербург и online
Крупнейшая в России конференция по тестированию ПО. Ожидаются доклады для специалистов разных профилей: QA-инженеров, разработчиков, тимлидов, директоров по качеству и др.

Mobius
01–02.11 — online
09–10.11 — Санкт-Петербург и online
Конференция для специалистов, связанных с мобильной разработкой: iOS- и Android-разработчиков, архитекторов мобильных приложений, специалистов по DevOps и др.

HolyJS
02–03.11 — online
11–12.11 — Санкт-Петербург и online
Конференция для JavaScript‑разработчиков. JS‑разработку здесь рассматривают в разных ракурсах — от конкретных фреймворков до борьбы с техдолгом.

PiterPy
07.11 — online
13–14.11 — Санкт-Петербург и online
Конференция для тех, кто пишет на Python и использует его в работе.

HighLoad
27–28.11
— Москва
Конференция для разработчиков высоконагруженных систем. Мероприятие направлено на обмен знаниями о технологиях, позволяющих одновременно обслуживать тысячи и миллионы пользователей.

TeamLead Conf
30.11–01.12
— Москва
Профессиональная конференция только для тимлидов.

@chulakov_dev
Всем привет!

В работе с React каждый разработчик сталкивается с механизмом batching. Знаете ли вы, что это такое?

Batching — это техника объединения нескольких вызовов обновления состояния в одну операцию. Это помогает оптимизировать производительность, уменьшая количество перерисовок компонента.

Рассмотрим пример:

export default function App() { 
const [username, setUsername] = useState("JohnDoe"); const [followers, setFollowers] = useState(1000);
const handleClear = () => {
setFollowers(0); setUsername("");
}
useEffect(() => { console.log("Компонент был отрендерен!");
});
return ( /* JSX код */ );
}

Казалось бы, при нажатии на кнопку clear компонент должен перерисоваться дважды из-за двух изменений состояния. Но благодаря batching в логах вы увидите лишь одно сообщение: «Компонент был отрендерен!»

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

Для приложений с частыми обновлениями состояния этот механизм становится настоящим спасением, обеспечивая плавность и отзывчивость интерфейса.

Но бывают ситуации, когда нам такое поведение не подходит. В этом случае React предоставляет метод с именем flushSync() в react-dom, который позволяет нам инициировать повторный рендеринг для определенного обновления состояния.

const handleClick = () => {
flushSync(() => { setClicked(!clicked);
// react will create a re-render here });
setCount(count + 1);
// react will create a re-render here};

Но flushSync() стоит использовать осторожно, так как он может значительно снизить производительность.

@chulakov_dev
Привет, друзья!

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

Ниже выбирайте свой вариант ответа👇🏻