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

Джулс Блом объяснила проблему проп-дриллинга и способ, как избежать этого, используя слоты. Также автор объяснил концепцию “родительского дерева” (parent tree) и “дерева владельцев” (owner tree) на следующем примере:

function App() {
return (
<Dashboard>
<DashboardContent currentUser={currentUser} />
</Dashboard>
);
}

function Dashboard({ children }) {
return (
<div>
<h2>Dashboard</h2>
{children} {/* DashboardContent will be rendered here */}
</div>
);
}


1. “Родительское дерево”: компонент или элемент, в который вложен другой компонент. Например, в <App> компонент <Dashboard> это родитель для <DashboardContent>.
2. “Дерево владельцев”: компонент, который рендерит другие компоненты. В примере это компонент <App>.

Поток данных - пропсы – следует из “дерева владельцев”. Поддержание плоской иерархии “дерева владельцев” путем декомпозиции компонентов может сократить путь потока данных, что приведет к лучшей инкапсуляции компонентов.

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

https://julesblom.com/writing/parents-owners-data-flow
👍71
SSR с Bun и React

Алекс Кейтс сделал пример приложения на Bun и React и реализовал SSR с роутингом.

Туториал, в котором по шагам показывают, как создать проект с помощью Bun и запустить сервер.

Создать проект с помощью Bun можно командой bun init. Она подготавливает проект, создает bun.lockb как lock файл package.json, а также index.ts и tsconfig.json, т.к. по умолчанию создает проекты на TypeScript.

https://alexkates.dev/server-side-rendering-ssr-with-bun-and-react
👍5
Тренинг по популярным JavaScript паттернам

Лидия Халли собрала популярные паттерны проектирования на JavaScript и React, а также паттерны по улучшению перфоманса и рендера.

Контент основан на Patterns.dev. Почти каждый паттерн можно проверить на понимание – выполнить задание и сравнить свой результат с решением на сайте.

https://javanoscriptpatterns.vercel.app/patterns
👍13
Релиз Next.js 13.5

Вышел релиз Next.js 13.5. Список изменений:

- Запуск dev сервера на 22% быстрее для App и Pages Router.
- HMR работает на 29% быстрее.
- Уменьшение потребления памяти сервера на 40%.
- Пофикшены более 438 багов.
- Оптимизированный импорт модулей. Более быстрое обновление в dev режиме и быстрый старт в проде при использовании модулей с большим количество экспортов, например для библиотек с иконками.
- Улучшение next/image. Функция unstable_getImgProps для продвинутых сценариев с изображениями без использования компонента <Image>. Например, можно использовать с тегом <picture>:

import { unstable_getImgProps as getImgProps } from 'next/image';

export default function Page() {
const common = { alt: 'Hero', width: 800, height: 400 };
const {
props: { srcSet: dark },
} = getImgProps({ ...common, src: '/dark.png' });
const {
props: { srcSet: light, ...rest },
} = getImgProps({ ...common, src: '/light.png' });

return (
<picture>
<source media="(prefers-color-scheme: dark)" srcSet={dark} />
<source media="(prefers-color-scheme: light)" srcSet={light} />
<img {...rest} />
</picture>
);
}


https://nextjs.org/blog/next-13-5
👍15
This media is not supported in your browser
VIEW IN TELEGRAM
Создание компонента тоста

Эмиль Ковальски в своем блоге рассказывает с какими проблемами столкнулся и как их решал при создании библиотеки тостов.

Для анимации использовал CSS переходы вместо keyframes, потому что CSS переходы можно прервать. Для создания эффекта наложения использовались CSS переменные для вычисления глубины вложенности. Для скрытия сообщений тостов используется пространственная согласованность: если что-то появляется снизу, оно должно и уходить в том же направление, т.е. снизу.

https://emilkowal.ski/ui/building-a-toast-component
👍22
This media is not supported in your browser
VIEW IN TELEGRAM
Эффект ввода текста с помощью React

В своем блоге Жюльен Тибо показал, как создать эффект ввода текста с помощью хука на React. Его можно использовать при создании чатов как анимацию загрузки или просто добавить динамики на сайт.

const useTypingEffect = (
text: string,
duration: number,
isTypeByLetter = false
) => {
const [currentPosition, setCurrentPosition] = useState(0);
const items = isTypeByLetter ? text.split("") : text.split(" ");

useEffect(() => {
setCurrentPosition(0);
}, [text]);

useEffect(() => {
if (currentPosition >= items.length) return;

const intervalId = setInterval(() => {
setCurrentPosition((prevPosition) => prevPosition + 1);
}, duration);

return () => {
clearInterval(intervalId);
};
}, [currentPosition, items, duration]);

return items.slice(0, currentPosition).join(isTypeByLetter ? "" : " ");
};


https://www.julienthibeaut.xyz/blog/create-text-typing-effect-with-react
👍121
Лучшие практики создания форм с react-hook-form

Обзор лучших практик создания больших форм с использованием react-hook-form и TypeScript:

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

2. Используйте пропы value и onChange для ввода и вывода для кастомных компонентов. Такой подход позволит бесшовно интегрировать react-hook-form.

3. Используйте проп name у полей формы для идентификации полей.

4. Используйте кастомный хук для типизации контекста формы:

import { useFormContext } from 'react-hook-form';
export const useMyFormContext = () => useFormContext<MyFormInterface>();


https://orizens.com/blog/best_practices_for_developing_complex_form-based_apps_with_react_hook_form_and_typenoscript_support/
👍8
Sugar High – легковесная подсветка кода

Sugar High - это легковесная подсветка кода на JSX, которая весит 1КБ после минификации и сжатия. Есть возможность кастомизации: можно поменять цвета токенов через CSS переменные.

https://sugar-high.vercel.app/
👍11
Тестирование своих библиотек локально с помощью Yalc

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

Yalc решает проблему локального тестирования библиотек и делает это довольно просто. Используйте команду yalc publish для публикации библиотеки и yalc add my-package в приложении, где хотите протестировать библиотеку.

https://github.com/wclr/yalc
👍121
Апдейт по компилятору React Forget

Сатья Гунасекаран, член основной команды React, рассказал почему затянулось создание компилятора React Forget и насколько он сложнее чем задумывался.

Компилятор будет поддерживать весь JavaScript, включая все его особенности. React Forget будет обратно совместим, поэтому приходится работать с существующим кодом, что усложняет задачу.

Есть задачи, которые на первый взгляд кажутся простыми, но на деле гораздо сложнее – это алиасы. Например, если создать алиас и присвоить переменную x другой переменной y:

function Component({a, b}) {
const x = [];
x.push(a);

const y = x;
y.push(b);

return <Foo x={x}/>;
}


Для компилятора есть вариант запомнить вычисление x отдельно и сделать его зависимостью для y:

// Неправильно
function Component({a, b}) {
const x = useMemo(() => {
const x = [];
x.push(a);
return x;
}, [a]);

const y = useMemo(() => {
const y = x;
y.push(b);
return y;
}, [x, b])

return <Foo x={x}/>;
}


Однако, правильным способом компиляции будет объединение этих вычислений в группу под одним useMemo:

function Component({a, b}) {
const x = useMemo(() => {
const x = [];
x.push(a);

const y = x;
y.push(b);
return y;
}, [a, b]);

return <Foo x={x}/>;
}


Этот пример довольно простой. А теперь представьте, что между x и y добавится поток управления или вызов функции, тогда такой код добавит еще больше сложности для анализа компилятору.

https://www.reddit.com/r/reactjs/comments/16nnh4z/comment/k1jbr4t/
3👍3
Интеграция веб-компонентов и React

Библиотека @lit/react позволяет безболезненно интегрировать веб-компоненты в React. Основная проблема при интеграции веб-компонентов в React – передача пропсов и прием событий. Данная библиотека решает эту проблему через функцию createComponent, которая мапит пропсы в веб-компонент.

Например, чтобы принимать событие onfoo нужно передать объект {onfoo: 'foo'}. Это означает, что событие onfoo будет вызываться каждый раз, когда кастомный элемент отправляет событие foo.

Пример интеграции веб-компонента и мапинг событий:

import * as React from 'react';
import {createComponent} from '@lit/react';
import {MyElement} from './my-element.js';

export const MyElementComponent = createComponent({
tagName: 'my-element',
elementClass: MyElement,
react: React,
events: {
onactivate: 'activate',
onchange: 'change',
},
});


Пример использования компонента в React:

<MyElementComponent
active={isActive}
onactivate={(e) => (isActive = e.active)}
/>


https://www.npmjs.com/package/@lit/react
👍10
Гайд по серверным компонентам

servercomponents.dev – сайт с гайдами по серверным компонентам, в которых объясняется, что это такое, чем это отличается от других решений и как этим пользоваться.
Основная информация для сайта была взята из разных источников, например из подкаста JavaScript Jabber, где Дэн Абрамов и Джо Савона обсуждали серверные компоненты в React. Причина этого в том, что на сайте документации react.dev отсутствует подробная информация про серверные компоненты, поэтому информацию про нее приходится искать в разных источниках.

Автор написал на следующие темы:
- Что такое серверные компоненты и чем они отличаются?
- Какую проблему решают серверные компоненты?
- Поэтапное внедрение серверных компонентов?

https://servercomponents.dev/
👍15
Релиз TanStack Query v5

Вышел релиз библиотеки TanStack Query v5 (react-query). Новая версия меньше предыдущей на 20% и более интуитивно понятна.

Критические изменения:
- Удалено большинство перегрузок функций и унифицировано использование useQuery и других хуков.
- Переименован параметр cacheTime на gcTime.
- Объединены keepPreviousData и placeholderData.
- Переименован loading в pending.
- Удалены колбеки из useQuery.

Новые фичи:
- Упрощение оптимистических изменений. Хук useMutation возвращает переданные аргументы в variables.
- Полная поддержка suspense. Появились хуки useSuspenseQuery, useSuspenseInfiniteQuery и useSuspenseQueries.
- Возможность предзагрузки нескольких страниц в Infinity Query с помощью prefetchInfiniteQuery.
- Новый DevTools.

https://tanstack.com/blog/announcing-tanstack-query-v5
🔥13👍5
Тонкости работы useTransition

В React появился хук useTransition, который позволяет делает UI переходы без зависаний. Хук возвращает флаг «загрузки» перехода и функцию для запуска перехода. Изменение стейта, вызванное в функции запуска перехода, выполняется в «фоне», пока нет активных критических изменений стейта.

const [isPending, startTransition] = useTransition();

// …

<TabButton
isLoading={isPending}
onClick={() => {
startTransition(() => {
setTab('projects');
});
}}
/>


Надя Макаревич сделала пример использования useTransition и показала с какой проблемой производительности можно столкнуться. В качестве примера рассматривается компонент с табами. Один из табов – тяжелый компонент, который долго рендерится. Если не использовать useTransition, то при переключении на тяжелый компонент UI фризится до окончания рендера. Если использовать useTransition, то UI не фризится, но возникает другая проблема: когда переключаемся на таб тяжелого компонента, а после на другой таб, то переключение будет занимать больше времени.

Дело в том, что хук useTransition возвращает два аргумента, первый из которых это флаг «загрузки» перехода. Когда мы вызываем функцию перехода, то происходит ре-рендер компонента с текущим состоянием, т.к. флаг «загрузки» перехода становится true. Из-за этого могут возникнуть проблемы с производительностью приложения. Чтобы избежать этого, используйте мемоизацию компонентов и их пропсов.

https://www.developerway.com/posts/use-transition
🔥5👍3
Как оптимизировали импорт пакетов в Next.js

В релизе Next.js 13.5 рассказали, что оптимизировали импорт пакетов. Это улучшило скорость локальной разработки и холодный запуск прод сборки, когда использовались пакеты, которые реэкспортировали большое количество модулей в баррель файле, например, иконки и UI библиотеки.

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

Первой попыткой оптимизировать импорт пакетов в Next.js был modularizeImports. Это опция позволяла настроить маппинг между именем экспорта и расположением его файла. То есть при компиляции проекта import { module2 } from 'my-lib’ превращался в import module2 from 'my-lib/module2’.

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

https://vercel.com/blog/how-we-optimized-package-imports-in-next-js
👍7
Rspress – генератор статических сайтов на Rspack

Команда ByteDance представила стабильную версию Rspress – генератора статических сайтов для документации. Под капотом использует Rspack – сборщик, написанный на Rust. Основные фичи генератора:
- Скорость сборки и HMR. Гораздо быстрее своих конкурентов.
- Поддержка MDX, а значит можно вставлять React компоненты в разметку.
- Встроенный полнотекстовый поиск на основе FlexSearch.
- Встроенная поддержка i18n и версионирования.
- Возможность кастомизации темы и сборки.

Основные конкуренты – Docusaurus, Nextra от Vercel и Vitepress.

https://rspress.dev/
👍6
Релиз Next.js 14

Вышел релиз Next.js 14. Основные изменения:

- Улучшение в Turbopack. Сборщик, написанный на Rust, стал на 53% быстрее запускаться и на 94% быстрее работать HMR.

- Серверные действия. Появилась возможность в компоненте на клиенте вызывать серверные действия внутри функции:

export default function Page() {
async function create(formData: FormData) {
'use server';
const id = await createItem(formData);
}

return (
<form action={create}>
<input type="text" name="name" />
<button type="submit">Submit</button>
</form>
);
}


Next.js сам разделит код на клиентский и серверный. Если используете TypeScript, то эта фича обеспечит полную сквозную безопасность типов между сервером и клиентом.

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


- Частичный пререндер. Появилась возможность частичного пререндера страницы с помощью Suspense. Например:

export default function Page() {
return (
<main>
<header>
<h1>My Store</h1>
<Suspense fallback={<CartSkeleton />}>
<ShoppingCart />
</Suspense>
</header>
{/* --snip-- */}
</main>
);
}


С частичным пререндером Next.js сгенерит статическую оболочку (shell) страницы, а вместо Suspense подставит fallback. Затем вместо fallback подставится динамический компонент, который пререндерится на сервере и стримится клиенту через тот же HTTP запрос, что и статическая оболочка.

- Улучшение метаданных

Появилась опция управлять мета-тегом viewport, colorScheme и themeColor через переменную viewport или функцию generateViewport:

export const viewport: Viewport = {
themeColor: 'black',
}

export default function Page() {}


https://nextjs.org/blog/next-14
12🔥7👍6
Оптимизация производительности браузерного расширения

Гайд по оптимизации браузерного расширения на React от Casca. Какие шаги команда предприняла:

- Оптимизация изображений. Чтобы не показывать пользователю тяжелые изображения, использовали Node.js библиотеку sharp для оптимизации и уменьшения изображений. Это увеличивает скорость загрузки изображений и уменьшает потребление памяти RAM.

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

- Предотвращение повторных ре-рендеров. Использование useMemo и реализации useEvent для мемоизации пропсов. Также реализовали свою библиотеку, работающую с массивом данных – keep-unchanged-values. Она предотвращает ререндеры, сохраняя неизмененные значения и обновляя только измененные данные.

https://cascaspace.substack.com/p/optimizing-performance-how-our-extension
👍5
Погружение в Storybook

Команда Formidable рассказала, как они работают со Storybook. Обычно принято использовать Storybook как витрину UI компонентов. Кроме этого, Storybook можно использовать для локальной разработки сложных UI компонентов и проведения визуального тестирования.

При работе со Storybook есть одна из сложностей – управление зависимостями компонентов, например контекст, CSS стили, работа сторонних скриптов. Для решения проблемы можно создать компонент-обертку, который будет настраивать окружение для компонентов. Например:


export const TestHarness = ({ children, route = "/", cart = {} }) => {
return (
<MemoryRouter initialEntries={[route]}>
<CartContext.Provider value={{ ...emptyCart, ...cart }}>
{children}
</CartContext.Provider>
</MemoryRouter>
);
};

Использовать его можно как декоратор:
// ~/.storybook/preview.ts
export const decorators = [
(Story, ctx) => <TestHarness {...ctx.parameters}><Story /></TestHarness>
];


В Storybook есть встроенная возможность визуального тестирования. В чем его преимущества:
- Нет необходимости в дополнительной настройке окружения для тестирования.
- Можно визуально увидеть работу тестов и использовать браузерную консоль и отладчик.
- Работает браузерное API и внедрить тестирование гораздо проще, чем использовать сторонние библиотеки.

Как это работает: у каждой Story есть функция play, внутри которой можно взаимодействовать со Story и выполнять проверки. Функция play выполняется при открытии Story и можно визуально увидеть ее работу. Пример:


// ~/components/Search.stories.tsx
export const WithSearchTerm: Story = {
async play({ canvasElement, step }) {
const ui = wrap(canvasElement); // The `wrap` function is defined later in this article

await step("type 'baguette' into the search box", async () => {
ui.searchbox.focus();
await userEvent.type(ui.searchbox, "baguette");
});
},
};


https://formidable.com/blog/2023/unlocking-the-power-of-storybook/
🔥12👍4
Создание игровых интерфейсов с помощью React

Для разработки игровых интерфейсов гораздо удобнее использовать экосистему React, HTML и CSS, чем делать это с помощью Unity. Например, Minecraft и Battlefield в той или иной форме используют React для своих игровых интерфейсов.

Есть два способа использовать React.

- Встраивание браузера или Webview. Если игра на ПК, то будет встраиваться Chromium. Если этот способ сильно утяжеляет игру, то можно воспользоваться Coherent Gameface. Это облегченная версия браузера, адаптированная к игровым UI и его можно использовать в Unity и Unreal Engine.

- Безбраузерный подход. Этот подход пропускает браузерный рендеринг и сразу интерпретирует JS в нативный UI код игрового движка. Наиболее полноценная библиотека для этого – OneJS. Он спроектирован для Unitiy и поддерживает TypeScript и Preact. Этот вариант работает более быстро, чем браузерный подход, но у него есть свои ограничения. Нельзя использовать сторонние библиотеки, Canvas, SVG и сложные CSS анимации.

https://www.adammadojemu.com/blog/intro-to-building-game-uis-with-react
👍61
Headless компонент: паттерн в React

В блоге Мартина Фаулера вышла статья от инженера Atlassian о паттерне Headless компонента.

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

При визуализации Headless компонент выглядит как тонкий слой по середине между UI и моделью данных.

Этот подход уже используется в нескольких библиотеках: React ARIA, Headless UI, React Table и Downshift.

В своей статье Цзюньтао Цю рассказал, как пошагово создать Headless компонент для элемента Dropdown, подключить его к UI и написать тесты.

https://martinfowler.com/articles/headless-component.html
👍16