Заметки про React – Telegram
Заметки про React
3.78K subscribers
34 photos
8 videos
485 links
Короткие заметки про React.js, TypeScript и все что с ним связано
Download Telegram
Самые популярные CSS-in-JS библиотеки в 2022 году

Опрос State of CSS выделил CSS-in-JS библиотеки, которые оказались наиболее часто используемыми среди фронтенд-разработчиков за 2022 год.

В тройке самых популярных оказались Styled Components, CSS Modules и Styled JSX. Алекс Ивановс написал по каждой библиотеке из рейтинга краткую информацию, пример использования и основные фичи.

https://stackdiary.com/css-in-js-libraries/
👍3👎3
React Email

Библиотека для создания email шаблонов с помощью React и TypeScript. Содержит набор готовых компонентов без стилей.

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

Для рендера шаблона используется функция render:

import { MyTemplate } from '../components/MyTemplate';
import { render } from '@react-email/render';

const html = render(<MyTemplate firstName="Jim" />, {
pretty: true,
});


В документации есть пример интеграции с почтовыми провайдерами: Nodemailer, SendGrid, Postmark и AWS SES. На сайте есть примеры готовых шаблонов.

https://react.email/
👍13
React Concurrency под капотом

Наконец-то опубликовался доклад, с которым я выступал осенью на Smashing Conf и performance.​now(). Ловите :) https://3perf.com/talks/react-concurrency/

Внутри — куча картинок про новые перфоманс-фичи React 18:
⚛️ Как именно работает useTransition() (с демкой в девтулзах и просмотром кода из React-а, да)
🧊 Как применять <Suspense>, чтобы ускорить гидрацию, и как его не применять
🫠 Почему Vue.js и Preact отказались реализовывать что-то похожее на React Concurrency

(и другое)
🔥9👍3
Варианты использования React ref callback

В блоге Джулс Блом вышел подробный гайд по вариантам использования ref callback.

Ref callback - это функция, которая передается хост элементу в атрибут ref. React вызывает эту функцию с ссылкой на DOM элемент при монтировании компонента и с null при размонтировании компонента.

Ref callback позволяет выполнять различные действия в момент, когда React прикрепляет или открепляет ref к DOM элементу. Например:
- Выполнить скролл или фокус к элементу при монтировании.
- Узнать DOM свойства при монтировании, например, размер элемента.
- Создание порталов в DOM элемент, созданный React.
- Поделиться DOM элементом с несколькими потребителями.

https://julesblom.com/writing/ref-callback-use-cases
👍83🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
React Wrap Balancer

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

https://github.com/shuding/react-wrap-balancer
🔥13👍4
Обработка ошибок с TypeScript

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

В TypeScript при обработке ошибки в try/catch тип ошибки всегда unknown:

try {
// --snip--
} catch (error) {
// error is unknown
}


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

В JavaScript много стандартных типов ошибок, например: ReferenceError, TypeError, SyntaxError. Также можно создавать свои собственные – пользовательские типы ошибок. При создании пользовательского типа ошибки расширяйтесь от стандартного класса Error, чтобы к ошибке прикреплялся стектрейс. Использование пользовательских ошибок позволяет более детально обрабатывать каждую ошибку и по разному реагировать на нее приложению. Пример:

export class ProjectError extends Error {
name: ErrorName;
message: string;
cause: any;

constructor({
name, message, cause
}: {
name: ErrorName;
message: string;
cause?: any
}) {
super();
this.name = name;
this.message = message;
this.cause = cause;
}
}

try {
throw new ProjectError({
name: "CREATE_PROJECT_ERROR",
message: "API Error"
});
} catch (error) {
if (error instanceof ProjectError) {
if (error.name === "CREATE_PROJECT_ERROR") {
toast(error.message);
}
}
}


https://engineering.udacity.com/handling-errors-like-a-pro-in-typenoscript-d7a314ad4991
👍8
Абсолютная абстракция форм в React

Гайд по созданию абстракций для форм от Брендана Аллана. В примерах для работы с формами автор использует react-hook-form, TypeScript и Zod.

Преимущество Zod в том, что он полностью поддерживает TypeScript, также есть утилитарный тип TypeOf для выведения типа из схемы. RHF поддерживает Zod через resolver.

Пример кастомного хука формы:

import { useForm, UseFormProps } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { TypeOf, ZodSchema } from 'zod';

interface UseZodFormProps<Z extends ZodSchema>
extends Exclude<UseFormProps<TypeOf<Z>>, 'resolver'> {
schema: Z;
}

export const useZodForm = <Z extends ZodSchema>({
schema,
...formProps
}: UseZodFormProps<Z>) =>
useForm({
...formProps,
resolver: zodResolver(schema),
});


https://www.brendonovich.dev/blog/the-ultimate-form-abstraction
👍13👎2
Практики композиции функций в React

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

- Используйте HoC для абстракции общей функциональности. Оборачивая в HoC мы можем добавить дополнительное поведение или пропсы, не изменяя оригинальный компонент.
- Объединяйте несколько HoC, используя композицию: compose(withFoo, withBar, withBaz)(Component).
- Один HoC делает только одну работу, используйте кастомные хуки для хранения состояния.
- Используйте техники функционального программирования, например, каррирование.

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

import { useEffect, useState } from 'react';

function useFetchUsers(url) {
const [users, setUsers] = useState([]);
useEffect(() => {
async function fetchData() {
const res = await fetch(url);
const data = await res.json();
setUsers(data.users);
}
fetchData();
}, [url]);
return users;
}

function withFetchUsers(Component) {
return function WrappedComponent(props) {
const users = useFetchUsers(props.url);
return <Component {...props} users={users} />;
}
}


https://medium.com/@rivoltafilippo/function-composition-in-large-react-applications-best-practices-and-real-world-examples-805aba8d37b1
👍6👎5
Библиотеки для визуализации

Подборка новых библиотек для визуализации данных для React:

visx

Библиотека от Airbnb, использующая под капотом D3. Состоит из множества небольших пакетов-примитивов как в D3. Поэтому при сборке приложения в конечный бандл попадет только код используемых пакетов.
На сайте заявляют, что это не готовая библиотека для построения графиков. С помощью этой библиотеки вы можете самостоятельно сделать свою библиотеку для построения графиков.

export default function Bars() {
// --snip--
const yScale = useMemo(
() =>
scaleLinear<number>({
range: [yMax, 0],
round: true,
domain: [0, Math.max(...data.map(getLetterFrequency))],
}),
[yMax],
);

return (
<noscript width={width} height={height}>
<GradientTealBlue id="teal" />
<Group top={verticalMargin / 2}>
{data.map((d) => {
// --snip--
const barHeight = yMax - (yScale(getLetterFrequency(d)) ?? 0);
const barX = xScale(letter);
return (
<Bar
key={`bar-${letter}`}
x={barX}
y={barY}
// --snip--
/>
);
})}
</Group>
</noscript>
);
}



mafs

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

function LineSegmentExample() {
const point1 = useMovablePoint([-1, -1])
const point2 = useMovablePoint([2, 1])

return (
<Mafs viewBox={{ y: [-1, 1] }}>
<CartesianCoordinates />
<Line.Segment
point1={point1.point}
point2={point2.point}
/>
{point1.element}
{point2.element}
</Mafs>
)
}
👍41
Все что вам нужно знать про конкурентный рендеринг

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

Для того чтобы активировать конкурентный рендеринг, нужно использовать либо переходы – useTransition или просто startTransition, либо отложенные значения – useDeferredValue. Эти API позволяют пометить обновления стейта низким приоритетом. Обновления стейта, которые объявляются вне фич конкурентного рендеринга, помечаются как обновления с высоким приоритетом.

Хенрику Йужи подробно разобрал API конкурентного рендеринга и описал крайние кейсы использования. Например, нужно понимать, что React рендерит в однопоточной среде. И если он начал рендерить компонент, то он будет рендерить его до конца без прерываний. Только по окончании рендера компонента React проверит, есть ли какая-либо высокоприоритетная задача в пуле задач. Как следствие, следует избегать задач, интенсивно использующих ЦП, которые выполняются в одном компоненте, а не распределены по нескольким компонентам.

https://blog.codeminer42.com/everything-you-need-to-know-about-concurrent-react-with-a-little-bit-of-suspense/
👍5🔥2
Почему мои Jest тесты такие медленные?

Запуск тестов через Jest может занять гораздо больше времени, чем хотелось бы. Чтобы разобраться в причинах медленной работы тестов, стоит понять на что Jest тратит время. При выполнении команды запуска тестов происходит следующее:

- Загрузка окружения (`jest-environment-jsdom`), построение графа зависимостей между файлами, загрузка плагинов и запуск дополнительных потоков.
- Заполнение кэша. Первый запуск будет длиться чуть дольше, т.к. Jest необходимо заполнить кэш. Процесс будет идти еще дольше, если происходит транспиляция TypeScript.
- Загрузка файла теста. Перед запуском теста необходимо загрузить или замокать все зависимости, указанные в файле теста и в файле setupTests.ts. Этот шаг можно оптимизировать.
- Выполнение теста.

Можно использовать Chrome DevTools, чтобы записать профиль производительности работы Jest и посмотреть, на что уходит больше всего времени. Автор подметил несколько основных кейсов, которые делают тесты медленными:
- Баррель файлы. Если вы импортируете компонент из библиотеки, то пишите полный путь к компоненту, а не используйте баррель файл. Баррель файл – это index.ts, который реэкспортирует все экспорты. Когда Jest встречает на своем пути баррель файл, то он загружает все экспорты, объявленные в нем.
- Проверьте setupTests.ts, он запускается перед каждым тестовым файлом.
- Если используете TypeScript, то уберите проверку типов при запуске тестов.
- Проверьте настройки Jest, возможно включены неэффективные для локальной разработки параметры запуска тестов.

https://blog.bitsrc.io/why-is-my-jest-suite-so-slow-2a4859bb9ac0
👍6
Ключ к хорошему дизайну компонента – эгоизм

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

Даниэль Ющик в статье на Smashing Magazine написал подробный гайд с примерами по созданию компонентов для дизайн системы.

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

- HTML управляет дизайном компонента. При разработке абстрактного компонента, наприме, Button не стоит отклоняться от нативного поведения базового элемента. Если у нативного элемента есть проп children, то и у абстрактного он должен быть. Иначе это делает компонент более жестким к изменениям, и новым разработчикам придется менять ментальную модель для работы с данным компонентом.

- children заботится сам о себе. Чем больше мы будем пытаться стилизовать содержимое компонента, тем сложнее это будет поддерживать и дорабатывать. Компонент должен стилизовать только себя, а не свое содержимое.

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

<Modal>
<Modal.CloseButton />
<Modal.Header> ... </Modal.Header>
<Modal.Main> ... <Modal.Main>
</Modal>


https://www.smashingmagazine.com/2023/01/key-good-component-design-selfishness/
👍9
Tamagui – универсальный UI kit

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

Библиотека tamagui состоит из ядра @tamagui/core и компилятора @tamagui/static. Компилятор предназначен для генерации и оптимизации CSS стилей для веба. Поддерживает кастомизации, можно изменить тему любого компонента.

https://tamagui.dev/
👍5👎1
Разбираемся в TypeScript с помощью теории множеств

Владимир Клепов написал подробный гайд про устройство типов в TypeScript. Для наглядности применяются определения из теории множеств: объединение A ∪ B , пересечение ​​A ∩ B, разность A \ B , подмножество и надмножество. Например:
- A extends B можно выразить как “A является подмножеством B”.
- Тип объединения | и пересечения & является объединением и пересечением двух множеств.
- Exclude<A, B> можно назвать разностью двух множеств, но с условием что A и B являются объединением.
- never – пустое множество. A & never = never и A | never = A.

Одним из интересных примеров можно выделить то, что TypeScript позволяет объявлять такие выражения: const x: {} = 9;. Это происходит из-за того, что тип {} не значит то же самое, что и пустой объект в JS. Это тип, в котором можно получить доступ к свойствам, но не важно к каким. Чтобы было понятнее, еще один похожий пример валидного выражения: const x: { toString(): string } = 9;. Это связано с тем, что TypeScript под капотом видит примитив как объект. Поэтому TypeScript позволяет выполнять такие выражения, т.к. благодаря автобоксингу JS выражение валидно и можно вызвать x.toString().

https://blog.thoughtspile.tech/2023/01/23/typenoscript-sets/
👍12
Astro 2.0

Вышла новая мажорная версия фреймворка Astro 2.0. Основные изменения:

Коллекция контента.
Это подход к организации контента, с помощью которого можно писать типобезопасный код в Markdown/MDX разметке. Коллекция контента – это любая папка внутри папки src/content, например “blog”, “newsletter”, "products". Внутри нее размещаются Markdown/MDX файлы с разметкой и полями. В корне src/content создается config файл, из которого экспортируется объект, где ключ - это название папки-коллекции, а значение - описание. В описании коллекции указывается Zod схема полей в разметке. После чего Astro проверяет поля в файлах разметки на правильность написания, а также предоставляет типобезопасное API запросов получения контента.

// src/content/config.ts
// –snip–
const blogCollection = defineCollection({ schema: blogSchema });
export const collections = {
'blog': blogCollection
};

// src/pages/work.astro
import { getCollection } from 'astro:content';
const allBlogPosts = await getCollection('blog');
// –snip–


Гибридный рендеринг
В Astro появилась возможность пререндера конкретной страницы. Эти страницы рендерятся во время сборки приложения, что приводит к экономии времени при загрузке страницы. Чтобы страница рендерилась во время сборки, нужно добавить запись:

export const prerender = true;


Другие изменения:
- Редизайн страницы ошибок
- Оптимизация Hot Module Reloading (HMR)
- Используется Vite 4.0

https://astro.build/blog/astro-2/
👍4
Новая документация React готова на 99%

По сообщению Дэна Абрамова для того, чтобы вывести новую документацию из беты, осталось сделать сайт лендинга.

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

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

https://beta.reactjs.org/
🔥33👍91👎1
Релиз TypeScript 5.0 Beta

На днях вышел релиз мажорной версии TypeScript 5.0 Beta. В этом релизе много новых фич. Кратко о некоторых фичах релиза:

Новый стандарт декораторов

В TS уже были декораторы, и они были доступны под флагом. В версии 5.0 декораторы будут доступны без флага, а те декораторы, которые были доступны под флагом, объявлены как легаси. Пример использования новых декораторов:

function loggedMethod<This, Args extends any[], Return>(
target: (this: This, ...args: Args) => Return,
context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>
) {
const methodName = String(context.name);

function replacementMethod(this: This, ...args: Args): Return {
console.log(`LOG: Entering method '${methodName}'.`)
const result = target.call(this, ...args);
console.log(`LOG: Exiting method '${methodName}'.`)
return result;
}

return replacementMethod;
}

class Person {
// --snip--

@bound
@loggedMethod
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
}


Для работы с декораторами добавлен новый тип ClassMethodDecoratorContext, который моделирует объект контекста, который принимают декораторы метода.
У метода может быть несколько декораторов. В примере сначала выполнится @loggedMethod, а потом @bound.
Декораторы можно использовать не только у метода, но и у класса и его полей.

const как параметр типа

В TS есть утверждение as const, которое делает выражение иммутабельным и говорит компилятору, что тип больше не будет расширяться.
В TS 5.0 можно добавить const как модификатор к объявлению типа параметра. Пример:

type HasNames = { names: readonly string[] };
function getNamesExactly<const T extends HasNames>(arg: T): T["names"] {
return arg.names;
}

// readonly ["Alice", "Bob", "Eve"]
const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });


При этом использование модификатора const не требует ограничения типа в виде readonly. Если не использовать readonly, то результат будет другим:

declare function fnBad<const T extends string[]>(args: T): void;

// 'T' будет 'string[]', а не 'readonly ["a", "b", "c"]'
fnBad(["a", "b" ,"c"]);


Несколько конфиг файлов в extends

Появилась возможность расширять tsconfig от несколько файлов:

{
"compilerOptions": {
"extends": ["a.json", "b.json", "c.json"]
}
}


В этом случае b.json расширяет a.json, а c.json расширяет b.json, а текущий конфиг расширяет c.json.

https://devblogs.microsoft.com/typenoscript/announcing-typenoscript-5-0-beta/
👍13
PR с заменой CRA на Vite

В репозитории reactjs.org стал популярным PR с предложением использовать Vite вместо CRA.

На это предложение ответил Дэн Абрамов. В своем комментарии он рассказал историю CRA и ее цели. Основной посыл заключается в том, что команда React не хочет забрасывать CRA, но и не хочет его рекомендовать. Важно создавать новые приложения с поддержкой SSG/SSR. В CRA же нет поддержки SSG/SSR.

Одной из целей развития CRA видят превращение его в CLI лаунчер: давать на выбор фреймворк для создания приложения: Next.js, Remix, CRA и т.д. Также возможно в будущем react-noscripts для сборки приложения перейдет на Vite.

https://github.com/reactjs/reactjs.org/pull/5487#issuecomment-1409720741
👍12
React рекурсивно ре-рендерит дочерние компоненты, но есть нюанс

Алекс Сидоренко в своем блоге сделал наглядную визуализацию того, как разделение компонентов и использование совместного размещения состояния (state colocation) позволяют предотвращать лишний рендер.

https://alexsidorenko.com/blog/react-render-children-prop/
👍9🔥21
React.js: Документальный фильм

Вышел документальный фильм про React. В нем рассказывается история создания библиотеки от самих разработчиков. В фильме снялись Том Оккино, Кристофер Чедо, Пит Хант, Себастьян Маркбоге, Дэн Абрамов и многие другие.

https://www.youtube.com/watch?v=8pDqJVdNa44
🔥8👍4
Гайд по обработке ошибок в React

В блоге Нади Макаревич вышел гайд по обработке ошибок в React.

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

Для того, чтобы предотвратить такие ситуации и отловить ошибку во время фазы жизненного цикла React, есть Error Boundaries. У него есть минусы: если возникла ошибка в колбеке или в асинхронном коде, то такая ошибка не дойдет до Error Boundaries:

const Component = () => {
useEffect(() => {
// Будет обработан ErrorBoundary
throw new Error('Destroy everything!');
}, [])

const onClick = () => {
// Не будет обработан ErrorBoundary
throw new Error('Hulk smash!');
}

useEffect(() => {
// Если возникнет ошибка, то не будет обработан ErrorBoundary
fetch('/bla')
}, [])

return <button onClick={onClick}>click me</button>
}

const ComponentWithBoundary = () => {
return (
<ErrorBoundary>
<Component />
</ErrorBoundary>
)
}


Чтобы направить ошибку из колбека или асинхронного кода в ErrorBoundary, можно перекинуть ошибку в React используя трюк:

const onClick = () => {
try {
//–snip–
} catch (e) {
// вызвать обновление стейта с выбросом ошибки
setState(() => throw e);
}
}


Чтобы самостоятельно не изобретать колесо, рекомендуется использовать библиотеку react-error-boundary. В ней уже решены основные проблемы, возникающие при обработке ошибок.

https://www.developerway.com/posts/how-to-handle-errors-in-react
🔥7👍5