Заметки про React – Telegram
Заметки про React
3.78K subscribers
34 photos
8 videos
485 links
Короткие заметки про React.js, TypeScript и все что с ним связано
Download Telegram
Как заменить useState на useRef и выиграть в производительности

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

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

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

Ситуации, когда стейт можно не использовать:
- Если значения нужны только в коллбэках, то используйте рефы.
- Буферизация изменений стейта. Если колбек вызывается слишком часто и в нем происходит изменение стейта, то возможно будет эффективнее запланировать изменение стейта используя requestAnimationFrame.
- Императивное изменение DOM узла. Например, если реализуется анимация, то гораздо эффективнее напрямую изменять стили DOM узла. Если для анимации использовать стейт, то потребуется очень много ререндеров компонента, что повлияет на производительность.

https://thoughtspile.github.io/2021/10/18/non-react-state/
This media is not supported in your browser
VIEW IN TELEGRAM
Расширение для отладки React приложений – Reactime

Инструмент позволяет отследить количество рендеров компонента и среднее время рендера. Киллер-фичей расширения является возможность переключения текущего состояния приложения – time-traveling, как в Redux DevTools.

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

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

https://chrome.google.com/webstore/detail/reactime/cgibknllccemdnfhfpmjhffpjfeidjga?hl=en-US

🇺🇸 https://medium.com/@liuedar/what-time-is-it-reactime-fd7267b9eb89
🔥1
Конференция React Conf 2021

Уже сегодня пройдет очередная ежегодная конференция React Conf 2021. Будет очень много тем про React 18.
Начало в 21:00 по Москве. Расписание докладов:

🗓️ 8 декабря 2021 г., 21:00 React 18 Keynote (Andrew Clark, Lauren Tan, Juan Tejada, Ricky Hanlon)
🗓️ 21:34 React 18 for app developers (Shruti Kapoor)
🗓️ 21:53 Streaming Server Rendering with Suspense (Shaundai Person)
🗓️ 22:12 The first React Working Group (Aakansha Doshi)
🗓️ 22:27 React Developer Tooling (Brian Vaughn)
🗓️ 22:27 React without memo (Xuan Huang)

🗓️ 23:00 React Docs Keynote (Rachel Nabors)
🗓️ 23:11 Things I learnt from the new React docs (Debbie O'Brien)
🗓️ 23:20 Learning in the Browser (Sarah Rainsberger)
🗓️ 23:31 The ROI of Designing with React (Linton Ye)
🗓️ 23:42 Interactive playgrounds with React (Delba de Oliveira)

🗓️ 9 декабря 2021 г., 0:00 Re-introducing Relay (Robert Balicki)
🗓️ 00:20 React Native Desktop (Eric Rozell, Steven Moyes)
🗓️ 00:36 On-device Machine Learning for React Native (Roman Rädle)

🗓️ 01:00 React 18 for External Store Libraries (Daishi Kato)
🗓️ 01:20 Building accessible components with React 18 (Diego Haz)
🗓️ 01:29 Accessible Japanese Form Components with React (Tafu Nakazaki)
🗓️ 01:39 UI Tools for Artists (Lyle Troxell)
🗓️ 01:49 Hydrogen + React 18 (Helen Lin)

https://conf.reactjs.org/
https://discord.gg/reactconf
Паттерн загрузки данных с Toast & SWR

Теодор Кларенс в своем блоге описывает подход к загрузке данных через кастомный хук и использование нотификаций.

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

Теодор Кларенс использовал react-hot-toast для отображения текущего статуса загрузки в виде нотификаций. Библиотека react-hot-toast умеет принимать промис и отображать сообщение в зависимости от состояния промиса. Для получения данных используется библиотека swr, которая умеет кэшировать ответы на запросы и обновлять кэш при повторном обращении.

const { data: pokemonData, isLoading } = useWithToast(
useSWR<PokemonList>('https://pokeapi.co/api/v2/pokemon?limit=20')
);


https://theodorusclarence.com/blog/react-loading-state-pattern
Почему стоит обратить внимание на Remix

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

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

Каждый модуль экспортирует API, которое будет использовать Remix при компиляции проекта. Экспортируемая переменная loader определяет функцию, которая будет вызываться на сервере перед рендерингом компонента, чтобы подготовить данные. Получить эти данные в компоненте можно через хук useLoaderData. Основной способ передачи информации с клиента на сервер – формы. Для обработки форм в модуле экспортируется переменная action. Внутри функции action можно валидировать поля, обращаться к базе данных и возвращать ответ. Ответ на стороне клиента можно получить через хук useActionData, в котором, например, могут приходить ошибки валидации. Экспорт default – это сам компонент.

Remix состоит из компилятора, серверного HTTP обработчика, серверного фреймворка и браузерного фреймворка. С помощью компилятора каждый модуль превращается в браузерный бандл и в бандл для серверного HTTP обработчика. Серверные HTTP обработчики позволяют запускать сервер как на Node.js серверах, так и на serverless серверах, например, Cloudflare Workers. Серверный фреймворк позволяет для каждого роута добавить функцию подготовки данных loader и функцию обработки формы action. Браузерный фреймворк позволяет работать приложению как SPA, дает возможность использовать хуки для взаимодействия с сервером, а также предзагружает ресурсы для страниц сайта.

Пример Remix модуля:

// routes/todos.js
import { redirect, Form } from "remix";

export async function loader() {
return fakeGetTodos();
}

export async function action({ request }) {
const body = await request.formData();
const todo = await fakeCreateTodo({
noscript: body.get("noscript")
});
return redirect(`/todos/${todo.id}`);
}

export default function Todos() {
const data = useLoaderData();
return (
<div>
<TodoList todos={data} />
<Form method="post">
<input type="text" name="noscript" />
<button type="submit">Create Todo</button>
</Form>
</div>
);
}


https://remix.run/docs/en/v1

🇺🇸 https://blog.plasmic.app/posts/why-remix-is-worth-your-attention/
Музей стейт менеджеров для React

Гант Лаборд создал репозиторий с примерами приложений, где используются разные стейт менеджеры. Все приложения одинаковые - стандартный туду лист, отличается только используемый в них стейт менеджер. Каждый пример можно посмотреть в работе на codesandbox и увидеть саму реализацию на github.

Сейчас в репозитории реализовано больше 35 стейт менеджеров для React. Также есть примеры реализации для React Native. Среди примеров есть как популярные Redux и Recoil, так и менее известные, например, microstates.

Репозиторий активно развивается и можно помочь, добавив свои примеры. Странно, что до сих пор еще нет nanostores и effector.

https://github.com/GantMan/ReactStateMuseum
Релиз Create React App 5

Вышла новая мажорная версия библиотеки create-react-app. Основные изменения:

- webpack 5
- Jest 27
- PostCSS 8
- ESLint 8
- Улучшения fast refresh
- Поддержка Tailwind

Для миграции нужно просто установить новую версию react-noscripts. Если будут ошибки, то нужно удалить node_modules и переустановить модули.

Как и любой мажорный релиз, новый react-noscripts содержит критические изменения. Например, была удалена поддержка Node.js 10 и 12 версии. В остальном, обещают что критические изменения не будут аффектить каждого пользователя.

https://github.com/facebook/create-react-app/releases/tag/v5.0.0
Опасности гидратации в React

Джошуа Комо разбирается с проблемами, которые могут возникнуть в процессе гидратации приложения на React. При гидратации React ожидает, что текущая структура DOM не будет меняться. Потому что после загрузки страницы в браузере, React рендерит все компоненты и пытается найти каждому компоненту пару в существующем DOM дереве, чтобы их связать между собой.

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

Джошуа Комо предлагает в компонентах с динамическими данными ничего не возвращать при первом рендере и вызывать повторный ререндер в хуке useEffect. В процессе гидратации и серверного рендеринга используется только первый рендер компонента. Хук useEffect вызывается после монтирования компонента, а это уже произойдет после гидратации компонента. Это решение помогает избежать мерцания при гидратации, а также предотвращает от багов в верстке.

function Navigation() {
const [hasMounted, setHasMounted] = React.useState(false);

React.useEffect(() => {
setHasMounted(true);
}, []);

if (!hasMounted) {
return null;
}

const user = getUser();

...
}


https://www.joshwcomeau.com/react/the-perils-of-rehydration/
Использование Rust в React приложениях

Джош Финни рассказывает, как использовать Rust в React приложениях. Для возможности использования Rust в вебе необходимо использовать модуль wasm-bindgen. Этот модуль генерирует биндинги для использования Rust программ через Wasm в вебе.

Использование Rust, как и например C, C++ или Go, через WebAssembly обеспечивает скорость выполнения кода близкой к нативной. WebAssembly также дает возможность переносить сложные вычисления за пределы JavaScript.

https://www.joshfinnie.com/blog/using-webassembly-created-in-rust-for-fast-react-components/

🇷🇺 https://habr.com/ru/company/timeweb/blog/594967/
Эффективный рендер больших списков

При работе с большими списками данных при проблемах с производительностью стоит обратить внимание на виртуализацию списка. Одна из таких библиотек для React – react-window. Библиотека умеет делать виртуализацию списка и сетки элементов с фиксированным или динамическим размером.

Виртуализация списка позволяет улучшить производительность страницы в целом, уменьшив количество отрендендеренных элементов. При скролле списка рендерятся в DOM только те элементы, которые находятся в поле видимости для пользователя. Если элемент покидает поле видимости, то он удаляется из DOM.

https://web.dev/virtualize-long-lists-react-window/
Архитектура веб-приложений patterns.dev

Адди Османи и Лидия Холли представили книгу с описанием шаблонов проектирования приложений. Книгу также можно почитать прямо на сайте проекта.

В ней есть как стандартные шаблоны проектирования, такие как Singleton, Factory и т.д., так и шаблоны рендеринга, например, рассматривается React Server Components.

В книге есть три раздела: шаблоны проектирования, рендеринга и производительности. В главах есть примеры реализации шаблонов на React или на ванильном JS.

https://www.patterns.dev/
Ленивая инициализация useRef

Владимир Клепов поделился техникой создания ленивой инициализации хука useRef. В отличие от useState, хук useRef не принимает функцию для инициализации значения. Ленивая инициализация может улучшить производительность компонента, т.к. позволяет вычислить значение рефа в момент его использования, а не при рендере компонента.

Есть несколько подходов к реализации данной техники:

- Установка значения рефа в useEffect. Минус в том, что значение рефа не будет доступно в первый рендер, в useLayoutEffect, а также в дочерних useEffect.

- Кастомный хук с инициализацией на месте. Минус подхода в том, что функция инициализации выполняется даже если значение рефа было не нужно. Также инициализация блокирует первый рендер.

const none = {};
function useLazyRef(init) {
const ref = useRef(none);
if (ref.current === none) {
ref.current = init();
}
return ref;
}


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

const ref = useState(() => ({ current: init() }))[0];


- Создать кастомный хук с полями аксессорами (accessor properties). Если у объекта задать геттер и сеттер на поле current и внутри использовать реф, то получится правильная ленивая инициализация рефа. Объект будет проинициализирован только при доступе к полю current.

https://thoughtspile.github.io/2021/11/30/lazy-useref/
👍2
Итоги 2021 года

Подготовил список наиболее интересных событий и статей за текущий год на канале для чтения на новогодних праздниках:

- Релиз фреймворка Remix в open source.
- Адди Османи и Лидия Холли представили проект с примерами использования паттернов проектирования patterns.dev.
- Вышла новая версия React Router 6.0.
- Прошла конференция React Conf 2021 (реплей).
- React 18 перешел в статус бета.
- Вышла новая мажорная версия Create React App 5.0.
- Опасности гидратации в React - читать.
- Гайд по разработке React приложений - читать.
- Как работает обработка ошибок в React - читать.

Всех с наступающим 2022 годом! 🎅☃️🎁
👍5
Использование React Server Components в Next.js 12

React Server Components (RSC) – это компоненты, которые выполняются на сервере, и на клиент передается уже отрендеренный компонент в формате JSON.
Рассмотрим основные особенности серверных компонентов. RSC не увеличивает размер бандла приложения, т.к. выполняются только на сервере. Компонент имеет доступ к бэкенду и базе данных. В серверных компонентах нельзя использовать состояние и эффекты, поэтому не поддерживаются хуки useState, useEffect и т.д.

Попробовать RSC пока что можно только вместе с каким-нибудь фреймворком, например, Next.js 12. В настройках конфига Next.js нужно включить экспериментальные фичи для поддержки конкурентного режима и серверных компонентов:

// next.config.js
module.exports = {
experimental: {
concurrentFeatures: true,
serverComponents: true,
},
}

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

В серверных компонентах использование Suspense позволяет не ждать загрузки всех данных для ответа клиенту. Suspense создает “слоты” в возвращаемом JSON. При получении данных и рендере компонентов внутри Suspense, сервер стримит JSON новых компонентов клиенту, который вставляет их в нужные слоты.

Не стоит путать серверные компоненты и техники пререндера контента, такие как Server-side rendering (SSR) или Static site generation (SSG). RSC позволяет отрендерить на сервере только часть компонентов на странице, а не всю страницу целиком.

https://blog.logrocket.com/react-server-components-nextjs-12/

демка: https://next-news-rsc.vercel.sh/ (github)
🔥10
Современные сборщики 2022

Собрал небольшую коллекцию инструментов-сборщиков, к которым стоит обратить внимание в 2022 году.

SWC – swc.rs
Предназначен для минификации, бандлинга и компиляции исходного кода веб-приложения.
Используется в Next.js 12, Parcel 2 и Deno. В Next.js заменяет Babel для бандлинга и Terser для минификации. В приложениях сборка ускорилась в 5 раз, а fast refresh в 3 раза. Компиляция кода в 17 раз быстрее чем Babel. Написан на Rust.
Поддерживает из коробки TypeScript, React.
Есть возможность интеграции в webpack для компиляции кода через ​​swc-loader. Пример.

Vite – vitejs.dev
Использует Rollup для сборки приложений и esbuild для предварительной сборки зависимостей. В Vite очень быстро работает dev-сервер и HMR. В dev режиме Vite не собирает бандл, а использует нативные ES модули. Есть готовые плагины для интеграции с React. Поддерживает TypeScript из коробки. Пример.

Romerome.tools
Швейцарский нож в сфере веб-разработки. Из коробки должен будет уметь бандлить, форматировать, компилировать, минифицировать, тестировать и т.д. Также будет поддержка TypeScript и React.
Проект изначально делался на TypeScript, но после был полностью переписан на Rust. Пока что частично работает только линтинг.

esbuildesbuild.github.io
Супер быстрый сборщик, написанный на Go. Из коробки поддерживает TypeScript и React, умеет делать минификацию. Есть возможность запуска dev-сервера: esbuild --bundle src/index.js --outfile=www/main.js --servedir=www
👍14🔥2
Blitz – фулстек фреймворк для React

Фреймворк Blitz сделан на базе Next.js, его ключевой особенностью является подход “Zero API”. Этот подход добавляет абстрактный слой работы с данными, позволяя избавиться от работы с REST или GraphQL. При разработке компонентов можно напрямую вызывать функции бэкенда. Во время сборки эти вызовы будут заменены на HTTP запросы к API, а само API будет сгенерировано автоматически.

Этот подход хорошо сочетается с TypeScript. При передаче параметров в функцию бэкенда будет происходить автоматическая проверка типов.

Функции бэкенда можно использовать по разному. В них можно вызывать напрямую изменения в БД, реализовать BFF, либо делать какие-то вычисления. По умолчанию для работы с БД предустановлена Prisma. Из коробки реализована поддержка авторизации пользователя по имейл/паролю.

https://blitzjs.com/
👎2🔥2
tRPC – замена REST и GraphQL

Заметил в Blitz интересный подход по работе с API и обнаружил библиотеку tRPC, которая делает точно так же, но не привязана к конкретному фреймворку.

Библиотека реализует технологию RPC по передаче данных. Все запросы делятся на получение и изменение данных и отправляются на один URL. Ответ на запрос приходит в формате JSON, из которого можно получить состояние ответа, сообщение об ошибке и данные. Если одновременно необходимо отправить несколько запросов, то их можно забатчить – объединить в один.

Главная особенность tRPC в том, что при написании типов параметров и ответов на сервере их можно использовать на клиенте. Делается это импортом типов, поэтому в клиентский бандл серверная часть кода не попадает.

Для React в tRPC есть готовые хуки useQuery и useMutation для получения и изменения данных. Также есть готовый плагин для Next.js для поддержки SSR и SSG.


// server/index.ts
import * as trpc from '@trpc/server';
import { z } from 'zod';

const appRouter = trpc
.router()
.query('getUser', {
input: (val: unknown) => {
if (typeof val === 'string') return val;
throw new Error(`Invalid input: ${typeof val}`);
},
async resolve(req) {
req.input; // string
return { id: req.input, name: 'Bilbo' };
},
})
.mutation('createUser', {
// validate input with Zod
input: z.object({ name: z.string().min(5) }),
async resolve(req) {
// use your ORM of choice
return await UserModel.create({
data: req.input,
});
},
});

export type AppRouter = typeof appRouter;


https://trpc.io/
👍7🔥4👎2
Обзор React Router v6

Тайлер МакГиннис написал подробный обзор про React Router v6.

React Router используется в 44% проектах в React. Проблема в том, что не все готовы уделить время на изучение того, как работает React Router. Поэтому МакГиннис собрал в одной статье основную информацию для базового понимания роутера.

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

https://ui.dev/react-router-tutorial/
👍6👎2
Решаем проблему проп дриллинга

Проп дриллинг – это анти-паттерн, при котором передача пропсов компоненту происходит через промежуточные компоненты, которые не используют получаемые пропсы, а только передают их в следующие компоненты.

Самый простой способ решить проблему проп дриллинга – использование контекста. Однако, при использовании контекста может возникнуть несколько проблем. Одна из них – это проблема переиспользования компонентов. Компонент, в котором используется контекст, зависит от значения контекста. Это означает, что если использовать компонент вне контекста или передать в контекст неправильное значение, то будет ошибка. Еще одна из проблем использования контекста – производительность. Изменение значения в провайдере будет провоцировать ререндер дочерних компонентов провайдера.

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

function App() {
const [data, setData] = useState("some state");

return (
<ParentComponent>
<ComponentOne>
<ComponentTwo data={data} />
</ComponentOne>
</ParentComponent>
);
}


https://blog.logrocket.com/solving-prop-drilling-react-apps/#container-components
👍8
Хочу провести небольшой опрос по инструментам тестирования на React проектах: