React Core Team не рекомендует CSS-in-JS runtime библиотеки
В недавнем Q&A интервью Дэн Абрамов поделился мнением насчет стилей в React приложениях. Основной посыл был в том, что если используются динамические стили, то лучше применять инлайновые стили у элемента. Если стили не динамические, то лучше использовать что-то, что компилируется в CSS при сборке приложения и не использует runtime.
Это утверждение совпадает с мнением Себастьяна Маркбоге, одного из ментейнера React. Он рекомендует выносить статичные стили при компиляции в
Одними из популярных CSS-in-JS библиотек, которые генерируют стили в runtime, являются Emotion и Styled Components. Одной из проблем этих библиотек является их производительность. Браузер во время загрузки страницы может параллельно парсить JS, CSS и HTML. В случае CSS-in-JS runtime библиотек сначала надо спарсить и запустить JS, который сгенерирует стили, и спарсить их отдельно.
В недавнем Q&A интервью Дэн Абрамов поделился мнением насчет стилей в React приложениях. Основной посыл был в том, что если используются динамические стили, то лучше применять инлайновые стили у элемента. Если стили не динамические, то лучше использовать что-то, что компилируется в CSS при сборке приложения и не использует runtime.
Это утверждение совпадает с мнением Себастьяна Маркбоге, одного из ментейнера React. Он рекомендует выносить статичные стили при компиляции в
<link rel="stylesheet">. Одними из популярных CSS-in-JS библиотек, которые генерируют стили в runtime, являются Emotion и Styled Components. Одной из проблем этих библиотек является их производительность. Браузер во время загрузки страницы может параллельно парсить JS, CSS и HTML. В случае CSS-in-JS runtime библиотек сначала надо спарсить и запустить JS, который сгенерирует стили, и спарсить их отдельно.
YouTube
Devs For Ukraine - Q&A with Dan Abramov
In this Q&A, Cassidy Williams and Sara Vieira ask Dan Abramov questions from the developer community about React, the web, the future, and more.
https://www.devsforukraine.io/
https://www.devsforukraine.io/
👍16👎4❤1
Применение принципов SOLID в React
Принципы SOLID находят свое применение не только в ООП, их можно применить и при разработке приложения React. Пользуясь этими принципами, можно обеспечить хорошую декомпозицию компонентов приложения.
В своем блоге Константин Лебедев интерпретировал принципы SOLID в коде React. Например, как можно применить принцип разделения интерфейса:
Компонент Thumbnail принимает объект video, хотя для работы данного компонента требуется только ссылка на изображение. Чтобы показать проблему, добавим новый тип видео в VideoList, у которого будет отличаться интерфейс объекта. В этом случае Thumbnail будет работать неправильно и его придется переделать. Сделаем так, чтобы Thumbnail принимал проп coverUrl – ссылку на изображение и будем передавать туда нужный проп в зависимости от типа видео:
Принцип разделения интерфейса отвечает за минимизацию зависимостей между компонентами системы, делая их менее связанными и переиспользуемыми.
https://konstantinlebedev.com/solid-in-react/
Принципы SOLID находят свое применение не только в ООП, их можно применить и при разработке приложения React. Пользуясь этими принципами, можно обеспечить хорошую декомпозицию компонентов приложения.
В своем блоге Константин Лебедев интерпретировал принципы SOLID в коде React. Например, как можно применить принцип разделения интерфейса:
// VideoList.tsx
type Video = {
noscript: string
duration: number
coverUrl: string
}
type Props = {
items: Array<Video>
}
const VideoList = ({ items }) => {
return (
<ul>
{items.map(item =>
<Thumbnail
key={item.noscript}
video={item}
/>
)}
</ul>
)
}
// Thumbnail.tsx
type Props = {
video: Video
}
const Thumbnail = ({ video }: Props) => {
return <img src={video.coverUrl} />
}
Компонент Thumbnail принимает объект video, хотя для работы данного компонента требуется только ссылка на изображение. Чтобы показать проблему, добавим новый тип видео в VideoList, у которого будет отличаться интерфейс объекта. В этом случае Thumbnail будет работать неправильно и его придется переделать. Сделаем так, чтобы Thumbnail принимал проп coverUrl – ссылку на изображение и будем передавать туда нужный проп в зависимости от типа видео:
type Props = {
items: Array<Video | LiveStream>
}
const VideoList = ({ items }) => {
return (
<ul>
{items.map(item => {
if ('coverUrl' in item) {
// it's a video
return <Thumbnail coverUrl={item.coverUrl} />
} else {
// it's a live stream
return <Thumbnail coverUrl={item.previewUrl} />
}
})}
</ul>
)
}
Принцип разделения интерфейса отвечает за минимизацию зависимостей между компонентами системы, делая их менее связанными и переиспользуемыми.
https://konstantinlebedev.com/solid-in-react/
Konstantinlebedev
Applying SOLID principles in React
As the software industry grows and makes mistakes, the best practices and good software design principles emerge and conceptualize to avoid repeating the same…
👍10
Date & Time picker для всех
UI библиотека от Adobe, React Spectrum, представила новые инструменты для работы с датой и временем для React – хуки useDateField и useTimeField. Также есть инструменты для работы с календарем useCalendar и useRangeCalendar. Помимо хуков есть стилизованные компоненты для работы с датой, временем и календарем.
Для работы с интернационализацией Adobe представила библиотеку
https://react-spectrum.adobe.com/blog/date-and-time-pickers-for-all.html
UI библиотека от Adobe, React Spectrum, представила новые инструменты для работы с датой и временем для React – хуки useDateField и useTimeField. Также есть инструменты для работы с календарем useCalendar и useRangeCalendar. Помимо хуков есть стилизованные компоненты для работы с датой, временем и календарем.
Для работы с интернационализацией Adobe представила библиотеку
@internationalized/date. В ней вместо использования стандартного объекта Date используются новые объекты для работы с датой и временем, с разным поведением и для разных кейсов. Например, CalendarDate представляет из себя только дату без времени, а Time только время без даты. Объекты поддерживают арифметические операции и их можно между собой сравнивать. В целом, получилась альтернатива Moment.js и другим подобным библиотекам. https://react-spectrum.adobe.com/blog/date-and-time-pickers-for-all.html
Adobe
Date and Time Pickers for All
We are very excited to announce the release of the React Aria and React Spectrum date and time picker components! This includes a full suite of fully featured components and hooks including calendars, date and time fields, and range pickers, all with a focus…
👍4
Как использовать Next.js мидлвары
В блоге Криса Николаса вышла статья о том, как можно использовать Next.js мидлвары. Файл мидлвара должен лежать в корневой папке проекта с названием middleware.ts.
Эта функция будет запускаться перед каждой загрузкой страницы, API роута или файла на сайте. Мидлвар не может возвращать Response. Также можно настроить работу мидлвара только для отдельных страниц, экспортировав config с массивом URL в файле middleware.ts:
Какие есть возможные варианты использования мидлваров:
- Редирект на другую страницу.
- Переписывание страницы, т.е. использование другой страницы для данного URL.
- Проверка UserAgent. Можно делать редирект или переписывание страницы на мобильную/десктопную версию сайта.
- Проверка доступа. Можно получить из запроса токен пользователя и проверить доступ к странице.
- Счетчик посещений.
https://www.ctnicholas.dev/articles/how-to-use-nextjs-middleware
В блоге Криса Николаса вышла статья о том, как можно использовать Next.js мидлвары. Файл мидлвара должен лежать в корневой папке проекта с названием middleware.ts.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware (request: NextRequest) {
return NextResponse.next()
}
Эта функция будет запускаться перед каждой загрузкой страницы, API роута или файла на сайте. Мидлвар не может возвращать Response. Также можно настроить работу мидлвара только для отдельных страниц, экспортировав config с массивом URL в файле middleware.ts:
export const config = {
matcher: ['/about', '/articles/:path*']
}
Какие есть возможные варианты использования мидлваров:
- Редирект на другую страницу.
- Переписывание страницы, т.е. использование другой страницы для данного URL.
- Проверка UserAgent. Можно делать редирект или переписывание страницы на мобильную/десктопную версию сайта.
- Проверка доступа. Можно получить из запроса токен пользователя и проверить доступ к странице.
- Счетчик посещений.
// Мидлвар проверки доступа
const secretKey = 'artichoke'
export function middleware (request: NextRequest) {
if (request.nextUrl.pathname === '/api/query') {
const headerKey = request.headers.get('secret-key')
// If secret keys match, allow access
if (headerKey === secretKey) {
return NextResponse.next()
}
// Otherwise, redirect to your custom error page
const url = request.nextUrl.clone()
url.pathname = '/unauthorised'
return NextResponse.redirect(url)
}
return NextResponse.next()
}
https://www.ctnicholas.dev/articles/how-to-use-nextjs-middleware
CTNicholas
How to Use Next.js Middleware • CTNicholas
With the release of Next.js 12, Vercel Edge Functions have been announced, allowing for
super speedy edge-optimised functions. They can also be used as helpful Next.js middleware functions.
In this article I'll explain what they are & how to use them, before…
super speedy edge-optimised functions. They can also be used as helpful Next.js middleware functions.
In this article I'll explain what they are & how to use them, before…
👍8
Подборка React компонентов и библиотек
Курируемый список компонентов и библиотек для разных кейсов. Мейнтейнеры собрали список из полезных компонентов и библиотек, которые решают проблемы в своей области.
Список разнообразный и разбит по категориям: от текстовых редакторов до древовидных меню и библиотек интернационализаций.
https://github.com/brillout/awesome-react-components
Курируемый список компонентов и библиотек для разных кейсов. Мейнтейнеры собрали список из полезных компонентов и библиотек, которые решают проблемы в своей области.
Список разнообразный и разбит по категориям: от текстовых редакторов до древовидных меню и библиотек интернационализаций.
https://github.com/brillout/awesome-react-components
GitHub
GitHub - brillout/awesome-react-components: Curated List of React Components & Libraries.
Curated List of React Components & Libraries. Contribute to brillout/awesome-react-components development by creating an account on GitHub.
👍5
HolyJS возвращается!
В ноябре JUG Ru Group организует конференцию для JavaScript‑разработчиков — HolyJS 2022. В программе — технические доклады и дискуссии о языках, архитектуре, графике, фреймворках и инструментах. На конференции соберутся все, кто программирует на JavaScript, — для фронтенда и не только.
Участники конференции любят обсуждать нетривиальные задачи и новые подходы в JavaScript-разработке. Есть интересные кейсы? Тогда подавайте заявку на выступление. Программный комитет поможет с подготовкой к выступлению: назначит персонального куратора, проведет ревью материала и организует репетиции.
Выбирайте тему выступления на сайте или предлагайте свои идеи — их обязательно рассмотрят.
Всем спикерам JUG Ru Group дарит билет на все конференции сезона в онлайне и офлайне.
А билеты можно купить здесь.
В ноябре JUG Ru Group организует конференцию для JavaScript‑разработчиков — HolyJS 2022. В программе — технические доклады и дискуссии о языках, архитектуре, графике, фреймворках и инструментах. На конференции соберутся все, кто программирует на JavaScript, — для фронтенда и не только.
Участники конференции любят обсуждать нетривиальные задачи и новые подходы в JavaScript-разработке. Есть интересные кейсы? Тогда подавайте заявку на выступление. Программный комитет поможет с подготовкой к выступлению: назначит персонального куратора, проведет ревью материала и организует репетиции.
Выбирайте тему выступления на сайте или предлагайте свои идеи — их обязательно рассмотрят.
Всем спикерам JUG Ru Group дарит билет на все конференции сезона в онлайне и офлайне.
А билеты можно купить здесь.
👍4
Event bus для React
Event Bus или шина событий – это шаблон проектирования, который используется для общения между компонентами, в то время как сами компоненты остаются слабо связанными.
Компонент может отправить сообщение в шину событий, не зная конечного получателя, как и сам получатель может не знать откуда пришло сообщение. Одним из вариантов использования шины событий – организация логирования в приложении.
В своем блоге Доу-Чи Лиу показал, как с нуля сделать шину событий на TypeScript и использовать в React компонентах для отправки аналитики.
https://dawchihliou.github.io/articles/event-bus-for-react
Event Bus или шина событий – это шаблон проектирования, который используется для общения между компонентами, в то время как сами компоненты остаются слабо связанными.
Компонент может отправить сообщение в шину событий, не зная конечного получателя, как и сам получатель может не знать откуда пришло сообщение. Одним из вариантов использования шины событий – организация логирования в приложении.
В своем блоге Доу-Чи Лиу показал, как с нуля сделать шину событий на TypeScript и использовать в React компонентах для отправки аналитики.
export default function Index() {
useEffect(() => {
const unsubscribeOnMapIdle = mapEventChannel.on('onMapIdle', () => {
logUserInteraction('on map idle.')
})
return () => {
unsubscribeOnMapIdle()
}
}, [])
// …
}
https://dawchihliou.github.io/articles/event-bus-for-react
dawchihliou.github.io
Event Bus for React
Event Bus is an interesting design pattern to build a lightweight event system. We will discover its use cases in React and build a type-safe Event Bus from scratch with TypeScript.
👎7👍4
React Query v4
Вышла новая версия библиотеки React Query. Точнее, теперь она называется TanStack Query. Разработчик провел ребрендинг и теперь библиотека не привязана к какому-то конкретному одному фреймворку. Помимо React планируется поддержка Vue, Svelte и Solid.
Кроме самого ребрендинга в 4ой версии появились новые фичи.
Поддержка офлайна. Query теперь может работать с любыми асинхронными данными и не зависит от того, доступна ли сейчас сеть. Также появился Network mode, который позволяет разрабатывать offline-first приложение. Это особенно удобно, если разрабатываете PWA приложение и кэшируете данные в Service Worker или в localStorage.
Улучшение производительности. С 4ой версии Tracked Queries стало поведением по умолчанию. При использовании данной фичи, компонент использующий Query будет ререндерится только при изменении использованных пропов query. Например, если вы не используете стейт isSuccess, то компонент не будет ререндерится, если он изменился. Более подробно написано здесь.
Персистентность. Есть возможность сохранять Query Cache во внешнее хранилище, например, в localStorage. Для того, чтобы подключить внешнее хранилище для кэша, нужно использовать адаптеры SyncStoragePersister и AsyncStoragePersister.
Поддержка React 18. В адаптере для React теперь используется useSyncExternalStore для поддержки конкурентного режима.
https://tanstack.com/blog/announcing-tanstack-query-v4
Вышла новая версия библиотеки React Query. Точнее, теперь она называется TanStack Query. Разработчик провел ребрендинг и теперь библиотека не привязана к какому-то конкретному одному фреймворку. Помимо React планируется поддержка Vue, Svelte и Solid.
Кроме самого ребрендинга в 4ой версии появились новые фичи.
Поддержка офлайна. Query теперь может работать с любыми асинхронными данными и не зависит от того, доступна ли сейчас сеть. Также появился Network mode, который позволяет разрабатывать offline-first приложение. Это особенно удобно, если разрабатываете PWA приложение и кэшируете данные в Service Worker или в localStorage.
Улучшение производительности. С 4ой версии Tracked Queries стало поведением по умолчанию. При использовании данной фичи, компонент использующий Query будет ререндерится только при изменении использованных пропов query. Например, если вы не используете стейт isSuccess, то компонент не будет ререндерится, если он изменился. Более подробно написано здесь.
Персистентность. Есть возможность сохранять Query Cache во внешнее хранилище, например, в localStorage. Для того, чтобы подключить внешнее хранилище для кэша, нужно использовать адаптеры SyncStoragePersister и AsyncStoragePersister.
Поддержка React 18. В адаптере для React теперь используется useSyncExternalStore для поддержки конкурентного режима.
https://tanstack.com/blog/announcing-tanstack-query-v4
tkdodo.eu
React Query Render Optimizations
An advanced guide to minimize component re-renderings when using React Query
👍9🔥4
Изучаем шейдеры и React Three Fiber
Three.js и его адаптер React Three Fiber используют WebGL для отрисовки сцен на экране. В свою очередь, WebGL использует шейдеры. Внутри Three.js уже есть встроенные шейдеры материалов: MeshNormalMaterial, MeshPhysicalMaterial и другие. Стандартные шейдеры ограничивают потенциал использования WebGL, поэтому Three.js позволяет создавать и использовать собственные шейдеры.
Максим Хекель в своем блоге рассказал про шейдеры, их виды и показал примеры их использования с React Three Fiber. Кроме самописных шейдеров существуют библиотеки для декларативного создания материалов – Lamina. С помощью композиции слоев можно создать новый материал, используя встроенные слои.
https://blog.maximeheckel.com/posts/the-study-of-shaders-with-react-three-fiber/
Three.js и его адаптер React Three Fiber используют WebGL для отрисовки сцен на экране. В свою очередь, WebGL использует шейдеры. Внутри Three.js уже есть встроенные шейдеры материалов: MeshNormalMaterial, MeshPhysicalMaterial и другие. Стандартные шейдеры ограничивают потенциал использования WebGL, поэтому Three.js позволяет создавать и использовать собственные шейдеры.
Максим Хекель в своем блоге рассказал про шейдеры, их виды и показал примеры их использования с React Three Fiber. Кроме самописных шейдеров существуют библиотеки для декларативного создания материалов – Lamina. С помощью композиции слоев можно создать новый материал, используя встроенные слои.
https://blog.maximeheckel.com/posts/the-study-of-shaders-with-react-three-fiber/
GitHub
GitHub - pmndrs/lamina: 🍰 An extensible, layer based shader material for ThreeJS
🍰 An extensible, layer based shader material for ThreeJS - pmndrs/lamina
👍3
Гайд по ре-рендерам React
В блоге Нади Макаревич вышел подробный гайд про ре-рендеры в React. В гайде рассказывается о том, какие бывают триггеры ре-рендера, приведены полезные паттерны для предотвращения ненужных ре-рендеров и показаны антипаттерны, которые ухудшают производительность приложения.
Есть несколько причин ре-рендера компонента в React:
- Изменение стейта.
- Ре-рендер родительского компонента.
- Изменено значение контекста.
- Изменение внутри хука. Изменения внутри хука будут отражаться на компоненте, который его использует.
Изменение пропсов не является причиной ре-рендера компонента, если не говорим о мемоизированных компонентах. Чтобы пропс изменился, нужно изменить стейт в родительском компоненте, что ведет к ре-рендеру компонента и его дочерних компонентов.
Одним из полезных паттернов предотвращения ре-рендера, особенно для тяжелых компонентов, является композиция и прокидывание компонента как проп. В базовом случае можно прокидывать компонент как children.
В компоненте
Стоит учитывать, что сам по себе ре-рендер не является проблемой, т.к. изменения в DOM браузера происходят после фазы коммита в React. Однако слишком частый ре-рендер может привести к тормозам и фризам UI, из-за чего приложением будет сложно пользоваться, особенно на слабых устройствах.
https://www.developerway.com/posts/react-re-renders-guide
В блоге Нади Макаревич вышел подробный гайд про ре-рендеры в React. В гайде рассказывается о том, какие бывают триггеры ре-рендера, приведены полезные паттерны для предотвращения ненужных ре-рендеров и показаны антипаттерны, которые ухудшают производительность приложения.
Есть несколько причин ре-рендера компонента в React:
- Изменение стейта.
- Ре-рендер родительского компонента.
- Изменено значение контекста.
- Изменение внутри хука. Изменения внутри хука будут отражаться на компоненте, который его использует.
Изменение пропсов не является причиной ре-рендера компонента, если не говорим о мемоизированных компонентах. Чтобы пропс изменился, нужно изменить стейт в родительском компоненте, что ведет к ре-рендеру компонента и его дочерних компонентов.
Одним из полезных паттернов предотвращения ре-рендера, особенно для тяжелых компонентов, является композиция и прокидывание компонента как проп. В базовом случае можно прокидывать компонент как children.
const ComponentWithScroll = ({ children }) => {
const [value, setValue] = useState({});
return (
<div onScroll={setValue}>
{children}
</div>
)
}
const App = () => {
return (
<ComponentWithScroll>
<HeavyComponent />
</ComponentWithScroll>
)
}
В компоненте
ComponentWithScroll проп children не будет зависеть от изменения стейта и вследствие чего не будет происходить его ре-рендер. Стоит учитывать, что сам по себе ре-рендер не является проблемой, т.к. изменения в DOM браузера происходят после фазы коммита в React. Однако слишком частый ре-рендер может привести к тормозам и фризам UI, из-за чего приложением будет сложно пользоваться, особенно на слабых устройствах.
https://www.developerway.com/posts/react-re-renders-guide
Developerway
React re-renders guide: everything, all at once
React re-renders "cheatsheet". Short denoscriptions with visual aid and code examples of: what re-renders are, what triggers them, most important re-renders related patterns and antipatterns to remember.
👍14
Обзор способов локализации React приложений
При разработке мультиязычного сайта необходимо выбрать инструмент для хранения и отображения переводов локалей сайта.
Для React есть несколько библиотек, которые позволяют работать с несколькими локалями:
react-i18next
Библиотека для перевода локалей на несколько языков:
- Возможность хранения переводов как локально в json файлах, так и на стороннем сервере, подгружая локали через плагин на бэкенде.
- Поддержка TypeScript: типизация ключей.
- Есть хуки для перевода строк и компонент Trans для перевода JSX дерева.
- Есть поддержка популярных фреймворков: Next.js, Gatsby, Remix.
react-intl
Библиотека для интернационализации приложения для разных локаций. Использует браузерное API Intl для интернационализации чисел, дат, относительного времени и плюрализации.
Есть как хуки, так и компоненты. Для каждого типа данных есть свой компонент. Например FormattedDate для дат, FormattedNumber для чисел, FormattedMessage для текстовых строк. Чаще всего пользуются последним – FormattedMessage. Также есть поддержка TypeScript.
LinguiJS
Библиотека использует ICU Message Format – синтаксис для выражения сообщений, как и react-intl. Библиотека предлагает использовать компонент Trans, внутри которого может быть JSX дерево. Используя babel макросы, LinguiJS переводит теги Trans в ICU MessageFormat. После чего вместо текстовых строк вставляет перевод. Например:
В файле c переводом, ключом перевода сообщения выше будет строка
Также в библиотеке есть CLI скрипты для извлечения сообщений из приложения и компиляции JS файла с локалями.
При разработке мультиязычного сайта необходимо выбрать инструмент для хранения и отображения переводов локалей сайта.
Для React есть несколько библиотек, которые позволяют работать с несколькими локалями:
react-i18next
Библиотека для перевода локалей на несколько языков:
- Возможность хранения переводов как локально в json файлах, так и на стороннем сервере, подгружая локали через плагин на бэкенде.
- Поддержка TypeScript: типизация ключей.
- Есть хуки для перевода строк и компонент Trans для перевода JSX дерева.
- Есть поддержка популярных фреймворков: Next.js, Gatsby, Remix.
import React from 'react';
import { useTranslation } from 'react-i18next';
export function MyComponent() {
const { t, i18n } = useTranslation();
// or const [t, i18n] = useTranslation();
return <p>{t('my translated text')}</p>
}
react-intl
Библиотека для интернационализации приложения для разных локаций. Использует браузерное API Intl для интернационализации чисел, дат, относительного времени и плюрализации.
Есть как хуки, так и компоненты. Для каждого типа данных есть свой компонент. Например FormattedDate для дат, FormattedNumber для чисел, FormattedMessage для текстовых строк. Чаще всего пользуются последним – FormattedMessage. Также есть поддержка TypeScript.
import {FormattedRelative, useIntl} from 'react-intl';
const MS_IN_DAY = 1e3 * 3600 * 24
const PostDate = ({date}) => {
const intl = useIntl()
return (
<span noscript={intl.formatDate(date)}>
<FormattedRelativeTime value={(Date.now() - date)/MS_IN_DAY} unit="day"/>
</span>
)
});
LinguiJS
Библиотека использует ICU Message Format – синтаксис для выражения сообщений, как и react-intl. Библиотека предлагает использовать компонент Trans, внутри которого может быть JSX дерево. Используя babel макросы, LinguiJS переводит теги Trans в ICU MessageFormat. После чего вместо текстовых строк вставляет перевод. Например:
<p>
<Trans id="msg.docs">Read the <a href="/docs">documentation</a>.</Trans>
</p>
В файле c переводом, ключом перевода сообщения выше будет строка
Read the <0>documentation</0>..Также в библиотеке есть CLI скрипты для извлечения сообщений из приложения и компиляции JS файла с локалями.
I18Next
Introduction | react-i18next documentation
👍4
Docusaurus 2.0
Вышла новая версия генератора статических сайтов Docusaurus. Он позволяет создавать сайты на React с фокусом на контент и поддерживает Markdown разметку из под коробки. По словам разработчиков, Docusaurus как create-react-app, но для создания документации, блогов и лендингов.
В новой версии появились новые фичи:
- MDX. Можно добавлять интерактивные React компоненты в Markdown разметку.
- Плагины. У Docusaurus модульная архитектура с системой плагинов. Основные фичи, такие как блог, документация, страницы и поиск можно улучшать плагинами.
- Темизация. Возможность очень гибкой кастомизации стилей, либо создание и использование своей собственной темы.
В целом, получился гибкий инструмент для создания документации и своих блогов, в котором уже есть все готовые компоненты для работы.
https://docusaurus.io/blog/2022/08/01/announcing-docusaurus-2.0
Вышла новая версия генератора статических сайтов Docusaurus. Он позволяет создавать сайты на React с фокусом на контент и поддерживает Markdown разметку из под коробки. По словам разработчиков, Docusaurus как create-react-app, но для создания документации, блогов и лендингов.
В новой версии появились новые фичи:
- MDX. Можно добавлять интерактивные React компоненты в Markdown разметку.
- Плагины. У Docusaurus модульная архитектура с системой плагинов. Основные фичи, такие как блог, документация, страницы и поиск можно улучшать плагинами.
- Темизация. Возможность очень гибкой кастомизации стилей, либо создание и использование своей собственной темы.
В целом, получился гибкий инструмент для создания документации и своих блогов, в котором уже есть все готовые компоненты для работы.
https://docusaurus.io/blog/2022/08/01/announcing-docusaurus-2.0
docusaurus.io
Announcing Docusaurus 2.0 | Docusaurus
Today we are extremely happy to finally announce Docusaurus 2.0! 🥳️
👍6
Различие между useEffect и useLayoutEffect
Хуки useEffect и useLayoutEffect предназначены для выполнения сайд-эффектов в компоненте и имеют одинаковые сигнатуру. Но цели их использования разные.
useEffect запускается асинхронно после отрисовки браузером DOM изменений.
useLayoutEffect запускается синхронно после DOM изменений, до отрисовки браузера.
Это значит, что если необходимо делать DOM изменения или какую-либо анимацию, то больше подходит useLayoutEffect. В остальных случаях необходимо использовать useEffect. Если выполнять DOM изменения в useEffect, то изменение отобразится в следующем тике браузерного рендера, что приведет к эффекту “мерцания”.
В React 18 было изменено поведение useEffect. Теперь он запускается синхронно, если это результат дискретного ввода. Дискретный ввод — это тип события, при котором результат одного события может повлиять на поведение следующего, например клик. Есть следующий пример:
Если запустить пример выше в React 17, то при клике на кнопку произойдет эффект “мерцания” – сначала тултип отобразится, потом расположится в нужной позиции. Если использоваться useLayoutEffect, то проблема исчезнет. Если запустить пример в React 18, то эффекта “мерцания” не будет и с useEffect, т.к. эффект произошел из-за дискретного ввода – клика по кнопке.
https://blog.saeloun.com/2022/07/28/difference-between-useeffect-and-useeffectlayout-hooks
Хуки useEffect и useLayoutEffect предназначены для выполнения сайд-эффектов в компоненте и имеют одинаковые сигнатуру. Но цели их использования разные.
useEffect запускается асинхронно после отрисовки браузером DOM изменений.
useLayoutEffect запускается синхронно после DOM изменений, до отрисовки браузера.
Это значит, что если необходимо делать DOM изменения или какую-либо анимацию, то больше подходит useLayoutEffect. В остальных случаях необходимо использовать useEffect. Если выполнять DOM изменения в useEffect, то изменение отобразится в следующем тике браузерного рендера, что приведет к эффекту “мерцания”.
В React 18 было изменено поведение useEffect. Теперь он запускается синхронно, если это результат дискретного ввода. Дискретный ввод — это тип события, при котором результат одного события может повлиять на поведение следующего, например клик. Есть следующий пример:
const App = () => {
const [showToolTip, setShowTooltip] = useState(false);
const buttonRef = useRef();
const tooltipRef = useRef();
useEffect(() => {
if (buttonRef.current == null || tooltipRef.current == null) return;
const { left, top } = buttonRef.current.getBoundingClientRect();
tooltipRef.current.style.left = ${left + 120}px;
tooltipRef.current.style.top = ${top - 20}px;
}, [showToolTip]);
return (
<div>
<button ref={buttonRef}
onClick={() => setShowTooltip(prevState => !prevState)}>
Toggle tooltip
</button>
{showToolTip &&
(<div ref={tooltipRef}>
This is a Tooltip!
</div>)}
</div>
)
};
Если запустить пример выше в React 17, то при клике на кнопку произойдет эффект “мерцания” – сначала тултип отобразится, потом расположится в нужной позиции. Если использоваться useLayoutEffect, то проблема исчезнет. Если запустить пример в React 18, то эффекта “мерцания” не будет и с useEffect, т.к. эффект произошел из-за дискретного ввода – клика по кнопке.
https://blog.saeloun.com/2022/07/28/difference-between-useeffect-and-useeffectlayout-hooks
Saeloun Blog
Understanding the difference between React useEffect and useLayoutEffect hooks
useEffect hook and useLayoutEffect hook differ in the timing of their invocation. useEffect hook runs asynchronously after the DOM has been painted whereas useLayoutEffect runs synchronously after all DOM mutations.
👍17
Mantine 5.0 – полнофункциональная библиотека компонентов
Mantine – библиотека компонентов для React 18, написанная на TypeScript и Emotion. Включает более 100 готовых компонентов и 40 хуков.
Библиотека разделена на модули, которые можно устанавливать по необходимости. Например, есть модули для работы с формами (аналог react-hook-form) и для работы с датами (компоненты календаря, выбора даты). Также есть модуль для обеспечения серверного рендера компонентов.
Библиотека поддерживает глобальную кастомизацию стилей через создание темы. Также можно кастомизировать отдельные компоненты в месте использования. Есть поддержка темной темы.
https://mantine.dev/
Mantine – библиотека компонентов для React 18, написанная на TypeScript и Emotion. Включает более 100 готовых компонентов и 40 хуков.
Библиотека разделена на модули, которые можно устанавливать по необходимости. Например, есть модули для работы с формами (аналог react-hook-form) и для работы с датами (компоненты календаря, выбора даты). Также есть модуль для обеспечения серверного рендера компонентов.
Библиотека поддерживает глобальную кастомизацию стилей через создание темы. Также можно кастомизировать отдельные компоненты в месте использования. Есть поддержка темной темы.
import { Slider } from '@mantine/core';
import { useHover } from '@mantine/hooks';
export function SliderHover() {
const { hovered, ref } = useHover();
return (
<Slider
defaultValue={40}
min={10}
max={90}
ref={ref}
label={null}
styles={{
thumb: {
transition: 'opacity 150ms ease',
opacity: hovered ? 1 : 0,
},
dragging: {
opacity: 1,
},
}}
/>
);
}
https://mantine.dev/
mantine.dev
👍11
Как избежать useEffect с помощью ref колбеков
Реф – это обертка, в которой может храниться любое значение, но чаще всего в ней хранят DOM узлы. В каждом HTML элементе есть зарезервированный проп ref, который позволяет получить доступ к DOM узлу после рендера компонента.
Одна из типичных задач при работе с рефом – сделать фокус у инпута при инициализации компонента. Один из вариантов, как это можно сделать, через useEffect:
В целом, это способ рабочий. Однако в более сложных ситуациях, когда реф будет передаваться во вложенный компонент, то может возникнуть ситуация, когда элемент с рефом будет рендерится лишь при определенном условии. Тогда useEffect вызовется с несуществующим рефом.
Более оптимальный способ обращения к рефу – через колбек реф. Концептуально реф у React элемента – это функция, которая вызывается после того, как компонент был отрендерен. Поэтому можно передать колбек в реф и получить доступ к DOM узлу только после рендера элемента.
Если компонент размонтируется, то колбек будет вызван еще раз с аргументом равным null, поэтому стоит проверять переданный аргумент перед использованием.
https://tkdodo.eu/blog/avoiding-use-effect-with-callback-refs
Реф – это обертка, в которой может храниться любое значение, но чаще всего в ней хранят DOM узлы. В каждом HTML элементе есть зарезервированный проп ref, который позволяет получить доступ к DOM узлу после рендера компонента.
const ref = React.useRef(null)
return <input ref={ref} defaultValue="Hello world" />
Одна из типичных задач при работе с рефом – сделать фокус у инпута при инициализации компонента. Один из вариантов, как это можно сделать, через useEffect:
const ref = React.useRef(null)
React.useEffect(() => {
ref.current?.focus()
}, [])
return <input ref={ref} defaultValue="Hello world" />
В целом, это способ рабочий. Однако в более сложных ситуациях, когда реф будет передаваться во вложенный компонент, то может возникнуть ситуация, когда элемент с рефом будет рендерится лишь при определенном условии. Тогда useEffect вызовется с несуществующим рефом.
Более оптимальный способ обращения к рефу – через колбек реф. Концептуально реф у React элемента – это функция, которая вызывается после того, как компонент был отрендерен. Поэтому можно передать колбек в реф и получить доступ к DOM узлу только после рендера элемента.
const ref = React.useCallback((node) => {
node?.focus()
}, [])
return <input ref={ref} defaultValue="Hello world" />
Если компонент размонтируется, то колбек будет вызван еще раз с аргументом равным null, поэтому стоит проверять переданный аргумент перед использованием.
https://tkdodo.eu/blog/avoiding-use-effect-with-callback-refs
tkdodo.eu
Avoiding useEffect with callback refs
Interacting with DOM nodes doesn't necessarily need useEffect
👍16
Создаем функцию контекста в JavaScript
React популяризировал идею распространения значений через контекст, с помощью которого можно избавиться от проп-дриллинга и синхронизировать состояние компонента в разных частях приложения.
Хотя вариант использования контекста в UI фреймворках очевиден, потребность подобного API существует и не только в UI фреймворках. Создадим свою версию Context API для фреймворка юнит тестирования:
После успешного прохождения теста в консоль должна выводиться запись:
Для того, чтобы это сообщение вывелось, нам нужно как-то прокинуть описание describe в функцию it. Для этого нам поможет концепция контекста.
Эвятар Алуш в своей статье на Smashing Magazine поделился своей реализацией контекста, которую он использовал в библиотеке для валидации форм Vest.
https://www.smashingmagazine.com/2022/08/react-context-propagation-javanoscript/
React популяризировал идею распространения значений через контекст, с помощью которого можно избавиться от проп-дриллинга и синхронизировать состояние компонента в разных частях приложения.
Хотя вариант использования контекста в UI фреймворках очевиден, потребность подобного API существует и не только в UI фреймворках. Создадим свою версию Context API для фреймворка юнит тестирования:
describe('calculator: Add', () => {
it("Should correctly add two numbers", () => {
expect(add(1, 1)).toBe(2);
});
});
После успешного прохождения теста в консоль должна выводиться запись:
“calculator: Add > ✅ Should correctly add two numbers”.Для того, чтобы это сообщение вывелось, нам нужно как-то прокинуть описание describe в функцию it. Для этого нам поможет концепция контекста.
Эвятар Алуш в своей статье на Smashing Magazine поделился своей реализацией контекста, которую он использовал в библиотеке для валидации форм Vest.
function createContext() {
let contextValue = undefined;
function Provider(value, callback) {
contextValue = value;
callback();
contextValue = undefined;
}
function Consumer() {
return contextValue;
}
return {
Provider,
Consumer
}
}
https://www.smashingmagazine.com/2022/08/react-context-propagation-javanoscript/
GitHub
GitHub - ealush/vest: Vest ✅ Declarative validations framework
Vest ✅ Declarative validations framework. Contribute to ealush/vest development by creating an account on GitHub.
👍6
Мигрируем с Create React App на Vite
Если вы задумывались о миграции приложения с Create React App на Vite, то Катал Мак Доннача в своем блоге собрал инструкцию как это сделать безболезненно.
Единственный минус Vite при работе с проектом на TypeScript – он не проверяет типы при сборке, а сразу транспилирует в JavaScript с помощью esbuild. Поэтому скорость сборки в 20-30 быстрее чем собирать с проверкой типов через tsc. Если это критично, то процесс сборки можно дополнить командой проверки типов
https://cathalmacdonnacha.com/migrating-from-create-react-app-cra-to-vite
Если вы задумывались о миграции приложения с Create React App на Vite, то Катал Мак Доннача в своем блоге собрал инструкцию как это сделать безболезненно.
Единственный минус Vite при работе с проектом на TypeScript – он не проверяет типы при сборке, а сразу транспилирует в JavaScript с помощью esbuild. Поэтому скорость сборки в 20-30 быстрее чем собирать с проверкой типов через tsc. Если это критично, то процесс сборки можно дополнить командой проверки типов
tsc --noEmit. В остальном, Vite умеет все то же самое что и CRA, но гораздо быстрее. https://cathalmacdonnacha.com/migrating-from-create-react-app-cra-to-vite
Everyday Frontend 🚀
Migrating from Create React App (CRA) to Vite
Learn how to migrate your CRA app over to Vite.
👍5
Используем React Query вместе с React Router
В React Router 6.4 добавится концепция получения данных – loader и action, как в фреймворке Remix.
Используя проп loader можно объявить, какие данные нужно запросить для отображения роута и получить их в роут через хук useLoaderData. Для изменения данных и их инвалидации используется проп action, а вызывается он при сабмите формы. Однако, React Router не берет на себя обязанность кэширования данных, поэтому имеет смысл использовать библиотеки запросов с кэшированием, например, React Query.
Доминик Дорфмайстер рассказал, как можно объединить React Router и React Query вместе, чтобы использовать преимущества обеих библиотек. React Router вызывает loader получения данных раньше, чем компонент монтируется, а React Query умеет кэшировать данные и дает возможность использовать API запроса, например, refetchOnWindowFocus.
Компонент, где объявляется роут:
Обратите внимание на то, что loader - не хук, поэтому не может использовать хук useQueryClient для получения инстанса клиента, и его нужно прокидывать в loader вручную.
На данный момент React Router 6.4 еще находится в бете, но уже можно посмотреть на сайте документации, как будут работать новые концепции получения данных.
https://tkdodo.eu/blog/react-query-meets-react-router
В React Router 6.4 добавится концепция получения данных – loader и action, как в фреймворке Remix.
Используя проп loader можно объявить, какие данные нужно запросить для отображения роута и получить их в роут через хук useLoaderData. Для изменения данных и их инвалидации используется проп action, а вызывается он при сабмите формы. Однако, React Router не берет на себя обязанность кэширования данных, поэтому имеет смысл использовать библиотеки запросов с кэшированием, например, React Query.
Доминик Дорфмайстер рассказал, как можно объединить React Router и React Query вместе, чтобы использовать преимущества обеих библиотек. React Router вызывает loader получения данных раньше, чем компонент монтируется, а React Query умеет кэшировать данные и дает возможность использовать API запроса, например, refetchOnWindowFocus.
// src/routes/contacts.jsx
import { useQuery } from '@tanstack/react-query'
import { getContact } from '../contacts'
// ⬇️ define your query
const contactDetailQuery = (id) => ({
queryKey: ['contacts', 'detail', id],
queryFn: async () => getContact(id),
})
// ⬇️ needs access to queryClient
export const loader =
(queryClient) =>
async ({ params }) => {
const query = contactDetailQuery(params.contactId)
// ⬇️ return data or fetch it
return (
queryClient.getQueryData(query.queryKey) ??
(await queryClient.fetchQuery(query))
)
}
export default function Contact() {
const params = useParams()
// ⬇️ useQuery as per usual
const { data: contact } = useQuery(contactDetailQuery(params.contactId))
// render some jsx
}
Компонент, где объявляется роут:
const queryClient = new QueryClient()
export default function Routes() {
return (
<Route
path="contacts/:contactId"
element={<Contact />}
// ⬇️ pass the queryClient to the route
loader={contactLoader(queryClient)}
/>
);
}
Обратите внимание на то, что loader - не хук, поэтому не может использовать хук useQueryClient для получения инстанса клиента, и его нужно прокидывать в loader вручную.
На данный момент React Router 6.4 еще находится в бете, но уже можно посмотреть на сайте документации, как будут работать новые концепции получения данных.
https://tkdodo.eu/blog/react-query-meets-react-router
👍11👎3
Почему React ре-рендерит
Джошуа Комо в своем блоге в двух частях рассказал, почему React ре-рендерит компоненты и как этого избежать.
Основная причина для рендера компонента – изменение стейта. При изменении стейта ре-рендерятся дочерние компоненты. Чтобы избежать лишнего ре-рендера компонента при рендере родительского, используйте мемоизацию – memo.
React оптимизирует процесс рендера, поэтому сам по себе ре-рендер не имеет большого значения. Однако в некоторых случаях ре-рендер “тяжелого” компонента может занять много времени и повлиять на производительность приложения. В случаях, когда нужно оптимизировать количество ре-рендеров, используют хуки useMemo и useCallback.
useMemo используется для кэширования вычислений между ре-рендерами. Также useMemo используется для сохранения ссылки на одно и то же значение между ре-рендерами для передачи в пропсы мемоизированного компонента. useCallback делает то же самое, что и useMemo, но только для функций.
https://www.joshwcomeau.com/react/why-react-re-renders/
https://www.joshwcomeau.com/react/usememo-and-usecallback/
Джошуа Комо в своем блоге в двух частях рассказал, почему React ре-рендерит компоненты и как этого избежать.
Основная причина для рендера компонента – изменение стейта. При изменении стейта ре-рендерятся дочерние компоненты. Чтобы избежать лишнего ре-рендера компонента при рендере родительского, используйте мемоизацию – memo.
React оптимизирует процесс рендера, поэтому сам по себе ре-рендер не имеет большого значения. Однако в некоторых случаях ре-рендер “тяжелого” компонента может занять много времени и повлиять на производительность приложения. В случаях, когда нужно оптимизировать количество ре-рендеров, используют хуки useMemo и useCallback.
useMemo используется для кэширования вычислений между ре-рендерами. Также useMemo используется для сохранения ссылки на одно и то же значение между ре-рендерами для передачи в пропсы мемоизированного компонента. useCallback делает то же самое, что и useMemo, но только для функций.
https://www.joshwcomeau.com/react/why-react-re-renders/
https://www.joshwcomeau.com/react/usememo-and-usecallback/
Joshwcomeau
Why React Re-Renders • Josh W. Comeau
In React, we don't update the DOM directly, we tell React what we want the DOM to look like, and React tackles the rest. But how exactly does it do this? In this tutorial, we'll unpack exactly when and why React re-renders, and how we can use this information…
👍7
React Awesome Reveal
Библиотека для React, которая добавляет анимацию раскрытия элемента используя Intersection Observer API. Библиотека использует Emotion для объявления стилей анимаций.
Также библиотека поддерживает Tree-shaking и серверный рендер. Поддерживается большинство стандартных анимаций из библиотеки Animate.css. Есть возможность каскадного применения анимации к дочерним элементам.
https://github.com/morellodev/react-awesome-reveal
Библиотека для React, которая добавляет анимацию раскрытия элемента используя Intersection Observer API. Библиотека использует Emotion для объявления стилей анимаций.
Также библиотека поддерживает Tree-shaking и серверный рендер. Поддерживается большинство стандартных анимаций из библиотеки Animate.css. Есть возможность каскадного применения анимации к дочерним элементам.
<Fade cascade>
<p>I enter first...</p>
<p>...then comes my turn...</p>
<p>...and finally you see me!</p>
</Fade>
https://github.com/morellodev/react-awesome-reveal
animate.style
Animate.css | A cross-browser library of CSS animations.
Animate.css is a library of ready-to-use, cross-browser animations for you to use in your projects. Great for emphasis, home pages, sliders, and attention-guiding hints.
👍5
Клиентский рендер vs серверный рендер
Альмог Габай провел подробное исследование CSR, в котором изучается потенциал приложений, которые рендерятся на клиенте, по сравнению с приложениями с серверным рендером.
Основной целью работы была возможность достичь хорошей производительности приложения и поддержки SEO в CSR приложениях.
В гайде написано про то, как можно настроить конфиг webpack для оптимальной работы приложения: создание vendor файла и preload чанков приложения. Для поддержки SEO необходима генерация sitemap.xml, которую можно создавать при сборке приложения.
Один из минусов серверного рендера - возможная долгая загрузка страницы. Одной из причин может быть большой размер документа, которую скачивает браузер. Другая причина может быть в ожидании сервером данных для генерации страницы.
https://github.com/theninthsky/client-side-rendering
Альмог Габай провел подробное исследование CSR, в котором изучается потенциал приложений, которые рендерятся на клиенте, по сравнению с приложениями с серверным рендером.
Основной целью работы была возможность достичь хорошей производительности приложения и поддержки SEO в CSR приложениях.
В гайде написано про то, как можно настроить конфиг webpack для оптимальной работы приложения: создание vendor файла и preload чанков приложения. Для поддержки SEO необходима генерация sitemap.xml, которую можно создавать при сборке приложения.
Один из минусов серверного рендера - возможная долгая загрузка страницы. Одной из причин может быть большой размер документа, которую скачивает браузер. Другая причина может быть в ожидании сервером данных для генерации страницы.
https://github.com/theninthsky/client-side-rendering
GitHub
GitHub - theninthsky/client-side-rendering: A case study of CSR.
A case study of CSR. Contribute to theninthsky/client-side-rendering development by creating an account on GitHub.
👍5