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
Миграция на React Router v6: подводные камни и альтернативы
Отличный гайд по миграции на React Router v6, в котором рассказывают про возможные проблемы, с которыми могут столкнуться разработчики при смене версии React Router в приложении.
Если приложение большое, то облегчить процесс миграции поможет библиотека react-router-dom-v5-compat. С помощью нее можно поэтапно мигрировать на новую версию, сохраняя работоспособность приложения.
https://habr.com/ru/company/alfa/blog/686954/
Отличный гайд по миграции на React Router v6, в котором рассказывают про возможные проблемы, с которыми могут столкнуться разработчики при смене версии React Router в приложении.
Если приложение большое, то облегчить процесс миграции поможет библиотека react-router-dom-v5-compat. С помощью нее можно поэтапно мигрировать на новую версию, сохраняя работоспособность приложения.
https://habr.com/ru/company/alfa/blog/686954/
Хабр
Как мы переходили на React-router v6: подводные камни и альтернативы
Мы перешли на шестую версии React-router. Это помогло нам решить несколько проблем, например, определение маршрутов в Switch рендерит точный маршрут, а не первое совпадение , а размер бандла...
🔥4👍1
Использование хука useSyncExternalStore
В React 18 появился новый хук useSyncExternalStore, который используется для чтения и подписки на внешние источники данных и совместим с конкурентным рендерингом. В основном он используется в библиотеках управления состояния, например, Redux для реализации селекторов. Также хук useSyncExternalStore может использоваться и в коде приложения для предотвращения лишних ререндеров компонента.
Для примера рассмотрим хук useLocation из библиотеки react-router. Он возвращает объект с несколькими атрибутами.
Возможно для работы компонента не нужны все атрибуты, однако при изменении любого из них произойдет ререндер компонента, даже если он не используется. Это может негативно повлиять на производительность приложения, особенно если этот хук используется в главном компоненте приложения App.js.
Для того чтобы избежать лишних ререндеров в данном примере, можно получать нужный атрибут через селектор, используя useSyncExternalStore. Хук принимает 3 аргумента:
- subscribe: функция, которая вызывает колбек при изменении значений.
- getSnapshot: функция, которая возвращает текущее значение стора.
- getServerSnapshot: функция, которая возвращает значение стора во время серверного рендеринга.
Чтобы реализовать через useSyncExternalStore селектор location, необходимо установить библиотеку history. Перенесем API history на аргументы useSyncExternalStore:
- history.listen: подписки на изменения.
- history: текущее значение.
Таким образом, реализация кастомного хука будет довольна проста:
В React 18 появился новый хук useSyncExternalStore, который используется для чтения и подписки на внешние источники данных и совместим с конкурентным рендерингом. В основном он используется в библиотеках управления состояния, например, Redux для реализации селекторов. Также хук useSyncExternalStore может использоваться и в коде приложения для предотвращения лишних ререндеров компонента.
Для примера рассмотрим хук useLocation из библиотеки react-router. Он возвращает объект с несколькими атрибутами.
function CurrentHash() {
const { hash } = useLocation();
return <div>{hash}</div>;
}
Возможно для работы компонента не нужны все атрибуты, однако при изменении любого из них произойдет ререндер компонента, даже если он не используется. Это может негативно повлиять на производительность приложения, особенно если этот хук используется в главном компоненте приложения App.js.
Для того чтобы избежать лишних ререндеров в данном примере, можно получать нужный атрибут через селектор, используя useSyncExternalStore. Хук принимает 3 аргумента:
- subscribe: функция, которая вызывает колбек при изменении значений.
- getSnapshot: функция, которая возвращает текущее значение стора.
- getServerSnapshot: функция, которая возвращает значение стора во время серверного рендеринга.
Чтобы реализовать через useSyncExternalStore селектор location, необходимо установить библиотеку history. Перенесем API history на аргументы useSyncExternalStore:
- history.listen: подписки на изменения.
- history: текущее значение.
Таким образом, реализация кастомного хука будет довольна проста:
function useHistorySelector(selector) {
return useSyncExternalStore(history.listen, () =>
selector(history)
);
}
function CurrentPathname() {
const pathname = useHistorySelector(
(history) => history.location.pathname
);
return <div>{pathname}</div>;
}
function CurrentHash() {
const hash = useHistorySelector(
(history) => history.location.hash
);
return <div>{hash}</div>;
}
legacy.reactjs.org
Hooks API Reference – React
A JavaScript library for building user interfaces
👍13🔥2
React и композиция функций
При создании приложения на React бывает необходимо делать сразу несколько вещей на каждой странице:
- проверять статус аутентификации пользователя;
- проверять фича-тоглы для отображения фич;
- логирование работы компонента;
- рендер лэйаута (навигация, боковое меню и т.д.)
Подобные вещи называют сквозными проблемами. Если страниц много, то на каждую страницу приходится копировать одинаковый код для решения подобных сквозных проблем.
Чтобы избавиться от дублирования кода, можно реализовать проверки и рендер в отдельных компонентах и вложить их в друг друга:
Недостаток такого подхода в том, что если изменится список сквозных проблем, то нужно обновить код всех страниц, где используются данные вложенные компоненты.
Более оптимальный вариант решения проблемы – использовать HOC. Это функция, которая принимает компонент и возвращает новый компонент. Новый компонент рендерит оригинальный компонент, но с дополнительной логикой.
Для каждой сквозной проблемы можно создать отдельный HOC и, используя функциональную композицию, объединить их все в один HOC:
Теперь решения сквозных проблем собраны и изменяются в одном месте. Для использования в компоненте нужно импортировать HOC withProviders:
https://medium.com/javanoscript-scene/why-every-react-developer-should-learn-function-composition-23f41d4db3b1
При создании приложения на React бывает необходимо делать сразу несколько вещей на каждой странице:
- проверять статус аутентификации пользователя;
- проверять фича-тоглы для отображения фич;
- логирование работы компонента;
- рендер лэйаута (навигация, боковое меню и т.д.)
Подобные вещи называют сквозными проблемами. Если страниц много, то на каждую страницу приходится копировать одинаковый код для решения подобных сквозных проблем.
Чтобы избавиться от дублирования кода, можно реализовать проверки и рендер в отдельных компонентах и вложить их в друг друга:
const MyPage = ({ user = {}, signIn, features = [], log }) => {
return (
<>
<AuthStatusProvider>
<FeatureProvider>
<LogProvider>
<StandardLayout>
<div className="content">{/* our actual page content... */}</div>
</StandardLayout>
</LogProvider>
</FeatureProvider>
</AuthStatusProvider>
</>
);
};
Недостаток такого подхода в том, что если изменится список сквозных проблем, то нужно обновить код всех страниц, где используются данные вложенные компоненты.
Более оптимальный вариант решения проблемы – использовать HOC. Это функция, которая принимает компонент и возвращает новый компонент. Новый компонент рендерит оригинальный компонент, но с дополнительной логикой.
Для каждой сквозной проблемы можно создать отдельный HOC и, используя функциональную композицию, объединить их все в один HOC:
const compose = (...fns) => (x) => fns.reduceRight((y, f) => f(y), x);
const withProviders = compose(
withUser,
withFeatures,
withLogger,
withLayout
);
export default withProviders;
Теперь решения сквозных проблем собраны и изменяются в одном месте. Для использования в компоненте нужно импортировать HOC withProviders:
const MyPage = ({ user = {}, signIn, features = [], log }) => {
return <>{/* our actual page content... */}</>;
};
const MyPageWithProviders = withProviders(MyPage);
https://medium.com/javanoscript-scene/why-every-react-developer-should-learn-function-composition-23f41d4db3b1
Medium
Why Every React Developer Should Learn Function Composition
Imagine you’re building a React application. There are a number of things you want to do on just about every page view of the application.
👍9
Обработка ошибок в React
В приложении могут возникать самые разные ошибки: от ошибки сети до неправильной работы хука в сторонней библиотеке. Если ваше приложение не будет обрабатывать такие ошибки, то оно может сломаться, отображая пользователю белый экран. В React для обработки ошибок используется Error Boundaries – механизм, когда ошибка в дереве компонентов всплывает до компонента обработчика ошибки и как-то обрабатывает его, например, отображая компонент-заглушку. Компонент обработки ошибок становится Error Boundaries, если он классовый и реализованы методы
У Error Boundaries есть недостаток, он не обрабатывает ошибки, которые возникли в следующих случаях:
- обработка событий;
- асинхронный код (setTimeout или requestAnimationFrame);
- во время SSR;
- возникли в Error Boundaries;
Также нет механизма повторного рендера дочернего компонента у Error Boundaries для восстановления приложения.
Чтобы обойти эти ограничения, можно использовать библиотеку react-error-boundary. Ее преимущество в том, что она позволяет восстановить работу приложения после ошибки. Также есть хук для обработки ошибок в асинхронном коде. Пример работы библиотеки:
https://github.com/bvaughn/react-error-boundary
В приложении могут возникать самые разные ошибки: от ошибки сети до неправильной работы хука в сторонней библиотеке. Если ваше приложение не будет обрабатывать такие ошибки, то оно может сломаться, отображая пользователю белый экран. В React для обработки ошибок используется Error Boundaries – механизм, когда ошибка в дереве компонентов всплывает до компонента обработчика ошибки и как-то обрабатывает его, например, отображая компонент-заглушку. Компонент обработки ошибок становится Error Boundaries, если он классовый и реализованы методы
static getDerivedStateFromError или componentDidCatch.У Error Boundaries есть недостаток, он не обрабатывает ошибки, которые возникли в следующих случаях:
- обработка событий;
- асинхронный код (setTimeout или requestAnimationFrame);
- во время SSR;
- возникли в Error Boundaries;
Также нет механизма повторного рендера дочернего компонента у Error Boundaries для восстановления приложения.
Чтобы обойти эти ограничения, можно использовать библиотеку react-error-boundary. Ее преимущество в том, что она позволяет восстановить работу приложения после ошибки. Также есть хук для обработки ошибок в асинхронном коде. Пример работы библиотеки:
import {ErrorBoundary} from 'react-error-boundary'
function ErrorFallback({error, resetErrorBoundary}) {
return (
<div role="alert">
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
)
}
const ui = (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onReset={() => {
// reset the state of your app so the error doesn't happen again
}}
>
<ComponentThatMayError />
</ErrorBoundary>
)
https://github.com/bvaughn/react-error-boundary
GitHub
GitHub - bvaughn/react-error-boundary: Simple reusable React error boundary component
Simple reusable React error boundary component. Contribute to bvaughn/react-error-boundary development by creating an account on GitHub.
👍15🔥2
Под капотом у Mobx. Пишем свою реактивную библиотеку с нуля
Когда начинаете использовать Mobx, то кажется, что внутри него используется какая-то магия. Но если посмотреть исходники, то окажется, что все написано на JS и используются стандартные объекты.
При создании Observable объекта и вывода его в консоль можно увидеть, что Observable оборачивает значение в Proxy. Внутри Proxy объекта находятся реакции, а внутри реакций находятся наблюдаемые значения и получается рекурсивная зависимость.
Григорий Гаврилов в статье на Хабре объяснил, как работает Mobx под капотом, реализовав основное API библиотеки.
https://habr.com/ru/post/689374/
Когда начинаете использовать Mobx, то кажется, что внутри него используется какая-то магия. Но если посмотреть исходники, то окажется, что все написано на JS и используются стандартные объекты.
При создании Observable объекта и вывода его в консоль можно увидеть, что Observable оборачивает значение в Proxy. Внутри Proxy объекта находятся реакции, а внутри реакций находятся наблюдаемые значения и получается рекурсивная зависимость.
Григорий Гаврилов в статье на Хабре объяснил, как работает Mobx под капотом, реализовав основное API библиотеки.
https://habr.com/ru/post/689374/
Хабр
Под капотом у Mobx. Пишем свою реактивную библиотеку с нуля
Первое мое знакомство с Mobx началось с удивления. Я не понимал всю магию библиотеки и задавал себе вопрос: “А как это возможно?”. Кажется, в ней используются какие-то подкапотные возможности JS или...
👍10
Будущее рендеринга в React
В текущий момент есть два подхода для рендеринга приложений на React:
- Client-Side Rendering. Сервер отдает базовый HTML и JS бандл и уже в браузере происходит рендеринг и получение данных по API.
- Server-side rendering. Получение данных и рендеринг приложения происходит на стороне сервера с помощью renderToString, который возвращает HTML для передачи клиенту. После получения HTML и JS на клиенте происходит гидратация.
У обоих из этих подходов есть свои плюсы и минусы в терминах Web Vitals, о которых пишет автор статьи. Новые подходы к рендеру приложения на React предназначены для решения основных минусов текущих подходов.
Streaming SSR. Новое API renderToPipeableStream позволяет в связке с Suspense разделить приложение на сегменты, каждый из которых будет рендериться независимо от остальных. При успешном рендере сегмента, HTML будет передаваться на клиент и вставляться в свое место в DOM.
Server components. Позволяет полностью рендерить компоненты приложения на сервере и не требует гидратации на клиенте. Так как компоненты рендерятся только на сервере, то имеют полный доступ к бэкенду и могут обращаться к БД. Один из вариантов использования такого подхода – тяжелые для рендера компоненты, которые будут быстрее рендериться на сервере, чем в браузере пользователя.
Server components еще находятся в альфа версии и недоступны для использования. Streaming SSR также еще официально не зарелизина. Команда React планирует, что разработчики не будут напрямую использовать новые подходы в своих проектах, т.к. они будут сложными в интеграции. Вместо этого, новые подходы рендера должны появиться в фреймворках, которые предоставят более простой интерфейс для работы. Например, новая версия Next.js Layouts RFC должна будет поддержать новые подходы рендера React.
https://prateeksurana.me/blog/future-of-rendering-in-react/
В текущий момент есть два подхода для рендеринга приложений на React:
- Client-Side Rendering. Сервер отдает базовый HTML и JS бандл и уже в браузере происходит рендеринг и получение данных по API.
- Server-side rendering. Получение данных и рендеринг приложения происходит на стороне сервера с помощью renderToString, который возвращает HTML для передачи клиенту. После получения HTML и JS на клиенте происходит гидратация.
У обоих из этих подходов есть свои плюсы и минусы в терминах Web Vitals, о которых пишет автор статьи. Новые подходы к рендеру приложения на React предназначены для решения основных минусов текущих подходов.
Streaming SSR. Новое API renderToPipeableStream позволяет в связке с Suspense разделить приложение на сегменты, каждый из которых будет рендериться независимо от остальных. При успешном рендере сегмента, HTML будет передаваться на клиент и вставляться в свое место в DOM.
Server components. Позволяет полностью рендерить компоненты приложения на сервере и не требует гидратации на клиенте. Так как компоненты рендерятся только на сервере, то имеют полный доступ к бэкенду и могут обращаться к БД. Один из вариантов использования такого подхода – тяжелые для рендера компоненты, которые будут быстрее рендериться на сервере, чем в браузере пользователя.
Server components еще находятся в альфа версии и недоступны для использования. Streaming SSR также еще официально не зарелизина. Команда React планирует, что разработчики не будут напрямую использовать новые подходы в своих проектах, т.к. они будут сложными в интеграции. Вместо этого, новые подходы рендера должны появиться в фреймворках, которые предоставят более простой интерфейс для работы. Например, новая версия Next.js Layouts RFC должна будет поддержать новые подходы рендера React.
https://prateeksurana.me/blog/future-of-rendering-in-react/
nextjs.org
Layouts RFC
Nested routes and layouts, client and server routing, React 18 features, and designed for Server Components.
👍8
Как получать данные в React
Надя Макаревич в своем блоге рассказала об оптимизации запросов на получение данных при инициализации вашего SPA приложения на React. В гайде не рассказывается о какой-то конкретной библиотеке для получения данных, а приводятся примеры паттернов получения данных и их подводные камни.
Например, можно вынести fetch за пределы компонента и тогда на момент инициализации компонента вероятнее всего данные уже будут получены. Этот способ можно использовать для наиболее критических ресурсов, которые нужно получить заранее.
https://www.developerway.com/posts/how-to-fetch-data-in-react
Надя Макаревич в своем блоге рассказала об оптимизации запросов на получение данных при инициализации вашего SPA приложения на React. В гайде не рассказывается о какой-то конкретной библиотеке для получения данных, а приводятся примеры паттернов получения данных и их подводные камни.
Например, можно вынести fetch за пределы компонента и тогда на момент инициализации компонента вероятнее всего данные уже будут получены. Этот способ можно использовать для наиболее критических ресурсов, которые нужно получить заранее.
const commentsPromise = fetch('/get-comments');
const Comments = () => {
useEffect(() => {
const dataFetch = async () => {
// just await the variable here
const data = await (await commentsPromise).json();
setState(data);
};
dataFetch();
}, [url]);
}
https://www.developerway.com/posts/how-to-fetch-data-in-react
Developerway
How to fetch data in React with performance in mind
Deep dive into data fetching in React. What is performance, fundamental libraries-agnostic patterns and techniques, how react lifecycle and browser limitations affect data fetching and apps rendering time and order.
👍6👎1