Удивительные вещи, связанные с React Hooks
https://dev.to/said_mounaim/awesome-things-related-to-react-hooks-30c4
https://dev.to/said_mounaim/awesome-things-related-to-react-hooks-30c4
Как проектировалось мидлвар подписки для Redux Toolkit
В Redux Toolkit 1.8 вышло новое API
В своем блоге один из разработчиков Redux Toolkit, Марк Эриксон, рассказал об истории данного API и этапах его разработки. Разработка данной фичи была начата 2.5 года назад и потребовала много итераций, чтобы определить, какие варианты использования он должен охватывать, как должен выглядеть общедоступный API и как реализовать функциональность.
В основе у Redux есть несколько основных библиотек для работы с сайд эффектами:
- Thunks: отправить экшен, получить (dispatch, getState) в аргументах и выполнить любую логику внутри функции.
- Sagas: напишите функцию генератор, которая на экшен вызывает сайд эффект функцию.
- Observables: напишите RxJs пайплайн, который на экшен вызывает сайд эффект функцию.
По умолчанию в Redux Toolkit был выбран Thunks, как самый простой вариант работы с сайд эффектами. При разработке API
https://blog.isquaredsoftware.com/2022/03/designing-rtk-listener-middleware/
В Redux Toolkit 1.8 вышло новое API
createListenerMiddleware
для подписки на отправку экшенов или изменения стейта. Это API должно стать более простой альтернативой использования вместо более популярных saga или observable.
// Create the middleware instance and methods
const listenerMiddleware = createListenerMiddleware()
// Add one or more listener entries that look for specific actions.
// They may contain any sync or async logic, similar to thunks.
listenerMiddleware.startListening({
actionCreator: todoAdded,
effect: async (action, listenerApi) => {
// Run whatever additional side-effect-y logic you want here
console.log('Todo added: ', action.payload.text)
// Can cancel other running instances
listenerApi.cancelActiveListeners()
// Run async logic
const data = await fetchData()
// Pause until action dispatched or state changed
if (await listenerApi.condition(matchSomeAction)) {
// Use the listener API methods to dispatch, get state,
// unsubscribe the listener, start child tasks, and more
listenerApi.dispatch(todoAdded('Buy pet food'))
listenerApi.unsubscribe()
}
},
})
В своем блоге один из разработчиков Redux Toolkit, Марк Эриксон, рассказал об истории данного API и этапах его разработки. Разработка данной фичи была начата 2.5 года назад и потребовала много итераций, чтобы определить, какие варианты использования он должен охватывать, как должен выглядеть общедоступный API и как реализовать функциональность.
В основе у Redux есть несколько основных библиотек для работы с сайд эффектами:
- Thunks: отправить экшен, получить (dispatch, getState) в аргументах и выполнить любую логику внутри функции.
- Sagas: напишите функцию генератор, которая на экшен вызывает сайд эффект функцию.
- Observables: напишите RxJs пайплайн, который на экшен вызывает сайд эффект функцию.
По умолчанию в Redux Toolkit был выбран Thunks, как самый простой вариант работы с сайд эффектами. При разработке API
createListenerMiddleware
команда Redux Toolkit хотела отделить экшены и сайд эффекты, т.е. смотрела в сторону redux-saga. Однако по сложности пользовательского API была цель сделать его близким к redux-thunk.https://blog.isquaredsoftware.com/2022/03/designing-rtk-listener-middleware/
Mark's Dev Blog
Idiomatic Redux: Designing the Redux Toolkit Listener Middleware
A dive into how we designed the API for the new RTK listener middleware
Обработка ошибок на React с помощью Error Boundary
https://dev.to/ms_yogii/handle-errors-gracefully-with-react-error-boundary-25mb
https://dev.to/ms_yogii/handle-errors-gracefully-with-react-error-boundary-25mb
Самая мощная шпаргалка по React JS
https://dev.to/bricourse/the-most-powerful-react-js-cheat-sheet-4ipd
https://dev.to/bricourse/the-most-powerful-react-js-cheat-sheet-4ipd
Как работает хук useInsertionEffect в React 18
CSS-in-JS библиотеки генерируют стили на лету и вставляют их в документ. Для этих библиотек важно знать, в какой момент можно вставлять теги <style> в документ, т.к. это может повлиять на производительность.
При добавлении или удалении CSS правил браузер пересчитывает стили у всех элементов. Для того чтобы избежать лишнего пересчета стилей для элементов на странице при изменении CSS правил, необходимо изменять их одновременно с другим изменением DOM, например, когда React мутирует DOM, перед чтением макета (например clientWidth) и до отрисовки в браузере.
Для того, чтобы добиться такого поведения, можно использовать хук
Внутри хука можно изменять глобальные DOM элементы, такие как <style> или <defs>. Он запускается перед хуком
https://blog.saeloun.com/2022/06/02/react-18-useinsertioneffect
✍️ @React_lib
CSS-in-JS библиотеки генерируют стили на лету и вставляют их в документ. Для этих библиотек важно знать, в какой момент можно вставлять теги <style> в документ, т.к. это может повлиять на производительность.
При добавлении или удалении CSS правил браузер пересчитывает стили у всех элементов. Для того чтобы избежать лишнего пересчета стилей для элементов на странице при изменении CSS правил, необходимо изменять их одновременно с другим изменением DOM, например, когда React мутирует DOM, перед чтением макета (например clientWidth) и до отрисовки в браузере.
Для того, чтобы добиться такого поведения, можно использовать хук
useInsertionEffect
. По сигнатуре он похож на useEffect
, но он запускается синхронно перед изменениями DOM.Внутри хука можно изменять глобальные DOM элементы, такие как <style> или <defs>. Он запускается перед хуком
useLayoutEffect
. Основное предназначение данного хука – изменение стилей в CSS библиотеках.
function useCSS(rule) {
useInsertionEffect(() => {
if (!isInserted.has(rule)) {
isInserted.add(rule);
document.head.appendChild(getStyleForRule(rule));
}
});
return rule;
}
function App() {
let className = useCSS(rule);
return <div className={className} />;
}
https://blog.saeloun.com/2022/06/02/react-18-useinsertioneffect
✍️ @React_lib
Saeloun Blog
Know about the useInsertionEffect hook in React 18
The useInsertionEffect hook in React 18 is mostly for CSS-in-JS libraries for inserting global DOM nodes like 'style' or SVG 'defs' in the document.
CSS-анимация как DOM-based фреймворк для анимации
https://medium.com/bbc-design-engineering/css-animations-as-a-dom-based-animations-framework-d6ef582c033a
✍️ @React_lib
https://medium.com/bbc-design-engineering/css-animations-as-a-dom-based-animations-framework-d6ef582c033a
✍️ @React_lib
Реальный пример работы startTransition
Ricky Hanlon показал подробный пример работы API startTransition из React 18, с объяснением работы API и того, как работает приложение в perfomance профиле.
В примере показан слайдер и компонент с «тяжелыми вычислениями», который занимает много времени для рендера, особенно на слабых устройствах. После изменения значения слайдера происходил ререндер тяжелого компонента. Самый оптимальный вариант рендера тяжелого компонента в React 17 через debounce, т.е. откладывая рендер на изменения слайдера.
В React 18 изменение значения слайдера достаточно обернуть в startTransition, и React уже сам выполнит эффективный рендер компонента. После рендера изменения значения слайдера, React рендерит transition результатов. Так как в этом изменение включен параллельный рендеринг, React делает три новые вещи:
- Yielding: каждые 5 мс React ставит работу рендера на паузу, чтобы дать браузеру сделать другую работу, например запустить промисы.
- Прерывание: React ставит рендер на паузу, если необходимо отрендерить более приоритетный компонент, например ползунок слайдера из примера.
- Отбрасывание старых результатов: когда React начинает рендерить после прерывания, то он отбрасывает старый компонент и рендерит новый.
https://github.com/reactwg/react-18/discussions/65
✍️ @React_lib
Ricky Hanlon показал подробный пример работы API startTransition из React 18, с объяснением работы API и того, как работает приложение в perfomance профиле.
В примере показан слайдер и компонент с «тяжелыми вычислениями», который занимает много времени для рендера, особенно на слабых устройствах. После изменения значения слайдера происходил ререндер тяжелого компонента. Самый оптимальный вариант рендера тяжелого компонента в React 17 через debounce, т.е. откладывая рендер на изменения слайдера.
В React 18 изменение значения слайдера достаточно обернуть в startTransition, и React уже сам выполнит эффективный рендер компонента. После рендера изменения значения слайдера, React рендерит transition результатов. Так как в этом изменение включен параллельный рендеринг, React делает три новые вещи:
- Yielding: каждые 5 мс React ставит работу рендера на паузу, чтобы дать браузеру сделать другую работу, например запустить промисы.
- Прерывание: React ставит рендер на паузу, если необходимо отрендерить более приоритетный компонент, например ползунок слайдера из примера.
- Отбрасывание старых результатов: когда React начинает рендерить после прерывания, то он отбрасывает старый компонент и рендерит новый.
https://github.com/reactwg/react-18/discussions/65
✍️ @React_lib
GitHub
Real world example: adding startTransition for slow renders · reactwg/react-18 · Discussion #65
In React 18 we announced a new startTransition API and shared a high-level overview of the problem it solves. In this post, we’re going to dive into a real-world example of speeding up a slow updat...
Инструменты для отладки React приложений
Если приложение работает медленно, то для поиска причины тормозов можно использовать специальные инструменты:
- React DevTools Базовый инструмент отладки React приложения. Умеет снимать perfomance профиль приложения, показать какой компонент отрендерился и сколько времени на это потребовалось.
- Why Did You Render (WDYR) Стандартного React DevTools может не хватать, поэтому в процесс отладки можно добавить WDYR. Этот инструмент находит компоненты, рендер которых можно избежать. Например, значением пропса компонента объявляется объект, поэтому этот компонент будет рендерится каждый раз, когда компонент создается. Найденную информацию WDYR отправляет в логи браузера.
- React Render Tracker Инструмент для отслеживания производительности приложения
✍️ @React_lib
Если приложение работает медленно, то для поиска причины тормозов можно использовать специальные инструменты:
- React DevTools Базовый инструмент отладки React приложения. Умеет снимать perfomance профиль приложения, показать какой компонент отрендерился и сколько времени на это потребовалось.
- Why Did You Render (WDYR) Стандартного React DevTools может не хватать, поэтому в процесс отладки можно добавить WDYR. Этот инструмент находит компоненты, рендер которых можно избежать. Например, значением пропса компонента объявляется объект, поэтому этот компонент будет рендерится каждый раз, когда компонент создается. Найденную информацию WDYR отправляет в логи браузера.
- React Render Tracker Инструмент для отслеживания производительности приложения
✍️ @React_lib
React Hooks: useState
Хук useState() предназначен для управления состоянием компонента. Данная функция возвращает пару геттер/сеттер - значение начального состояния и функцию для обновления этого значения. Функцию имеет следующую сигнатуру: const [value, setValue] = useState(defaultValue).
Обновление одного состояния
Обновление нескольких состояний
Обновление объекта состояния
Счетчик
Более сложный пример
✍️ @React_lib
Хук useState() предназначен для управления состоянием компонента. Данная функция возвращает пару геттер/сеттер - значение начального состояния и функцию для обновления этого значения. Функцию имеет следующую сигнатуру: const [value, setValue] = useState(defaultValue).
Обновление одного состояния
const UpdateState = () => {
const [age, setAge] = useState(19)
const handleClick = () => setAge(age + 1)
return (
<>
<p>Мне {age} лет.</p>
<button onClick={handleClick}>Стать старше!</button>
</>
)
}
Обновление нескольких состояний
const MultipleStates = () => {
const [age, setAge] = useState(19)
const [num, setNum] = useState(1)
const handleAge = () => setAge(age + 1)
const handleNum = () => setNum(num + 1)
return (
<>
<p>Мне {age} лет.</p>
<p>У меня {num} братьев и сестер.</p>
<button onClick={handleAge}>Стать старше!</button>
<button onClick={handleNum}>Больше братьев и сестер!</button>
</>
)
}
Обновление объекта состояния
const StateObject = () => {
const [state, setState] = useState({ age: 19, num: 1 })
const handleClick = (val) =>
setState({
...state,
[val]: state[val] + 1
})
const { age, num } = state
return (
<>
<p>Мне {age} лет.</p>
<p>У меня {num} братьев и сестер.</p>
<button onClick={() => handleClick('age')}>Стать старше!</button>
<button onClick={() => handleClick('num')}>
Больше братьев и сестер!
</button>
</>
)
}
Счетчик
const CounterState = () => {
const [count, setCount] = useState(0)
return (
<>
<p>Значение счетчика: {count}.</p>
<button onClick={() => setCount(0)}>Сбросить</button>
<button onClick={() => setCount((prevVal) => prevVal + 1)}>
Увеличить (+)
</button>
<button onClick={() => setCount((prevVal) => prevVal - 1)}>
Уменьшить (-)
</button>
</>
)
}
Более сложный пример
const Profile = () => {
const [profile, setProfile] = useState({
firstName: 'Иван',
lastName: 'Петров'
})
const handleChange = ({ target: { value, name } }) => {
setProfile({ ...profile, [name]: value })
}
const { firstName, lastName } = profile
return (
<>
<h1>Профиль</h1>
<form>
<input
type='text'
value={firstName}
onChange={handleChange}
name='firstName'
/> <br />
<input
type='text'
value={lastName}
onChange={handleChange}
name='lastName'
/>
</form>
<p>
Имя: {firstName} <br />
Фамилия: {lastName}
</p>
</>
)
}
✍️ @React_lib
Библиотеки для работы с формами в React
- Formik. Одна из наиболее популярных библиотек для работы с формами. Умеет отправлять форму асинхронно, поддерживает TypeScript, а также валидацию через Yup или Joi. В Formik входит набор компонентов для создания формы: Form, Field, ErrorMessage, но так же форму можно создать используя хук useFormik.
- React Hook Form. Гибкая библиотека для создания форм черех хуки. Поддерживает TypeScript и React Native. Умеет делать валидацию полей и формы, подключается к нативным инпутам через ref атрибут. Если инпут кастомный, например, из Material UI, то предлагает использовать обертку в виде компонента Controller.
- React Final Form. Библиотека использует паттерн Observer для обновления состояния компонентов и ре-рендера. Поддерживает валидацию полей и формы, в состав библиотеки входят как компоненты Form, Field, так и хуки. Мейнтенер библиотеки Erik Rasmussen, который также был автором Redux Form, считает ключевой фичей React Final Form высокую производительность.
✍️ @React_lib
- Formik. Одна из наиболее популярных библиотек для работы с формами. Умеет отправлять форму асинхронно, поддерживает TypeScript, а также валидацию через Yup или Joi. В Formik входит набор компонентов для создания формы: Form, Field, ErrorMessage, но так же форму можно создать используя хук useFormik.
- React Hook Form. Гибкая библиотека для создания форм черех хуки. Поддерживает TypeScript и React Native. Умеет делать валидацию полей и формы, подключается к нативным инпутам через ref атрибут. Если инпут кастомный, например, из Material UI, то предлагает использовать обертку в виде компонента Controller.
- React Final Form. Библиотека использует паттерн Observer для обновления состояния компонентов и ре-рендера. Поддерживает валидацию полей и формы, в состав библиотеки входят как компоненты Form, Field, так и хуки. Мейнтенер библиотеки Erik Rasmussen, который также был автором Redux Form, считает ключевой фичей React Final Form высокую производительность.
✍️ @React_lib
formik.org
React hooks and components for hassle-free form validation. The world's leading companies use Formik to build forms and surveys in React and React Native.
Пример использования useDeferredValue
Дэн Абрамов поделился примером использования хука useDeferredValue из React 18:
Используйте
✍️ @React_lib
Дэн Абрамов поделился примером использования хука useDeferredValue из React 18:
function Form() {
const [state, setState] = useState({ value: "hello" })
const deferredState = useDeferredValue(state)
// ...
Используйте
deferredState
в компонентах, рендер которых не срочный: например, вычисление сложной логики. Это поведение напоминает debounce. Использовать state
напрямую можно в элементах пользовательского ввода, например, input. ✍️ @React_lib
GitHub
Patterns for startTransition · reactwg/react-18 · Discussion #100
One major use case for startTransition is to update an input instantaneously while things that depend on that input's value are possibly delayed: function TransInput({ value, onChange }) { cons...
UI-компоненты для React: топ-10 библиотек и фреймворков
https://dev.to/nilanth/10-react-packages-with-1k-ui-components-2bf3
✍️ @React_lib
https://dev.to/nilanth/10-react-packages-with-1k-ui-components-2bf3
✍️ @React_lib
Пишем продвинутый планировщик с использованием React, Nest и NX. Часть 1: настройка проекта
В серии статей мы поэтапно разработаем продвинутое приложение-планировщик. Сначала создадим и настроим монорепозиторий c помощью NX, разработаем интерфейс с помощью React, добавим backend на основе NestJS, и, наконец, подключим базу данных MongoDB.
✍️ @React_lib
В серии статей мы поэтапно разработаем продвинутое приложение-планировщик. Сначала создадим и настроим монорепозиторий c помощью NX, разработаем интерфейс с помощью React, добавим backend на основе NestJS, и, наконец, подключим базу данных MongoDB.
✍️ @React_lib
Погружаемся в React Suspense API
https://blog.bitsrc.io/understanding-the-suspense-api-in-react-18-bbea3f6f6df1
✍️ @React_lib
https://blog.bitsrc.io/understanding-the-suspense-api-in-react-18-bbea3f6f6df1
✍️ @React_lib
Error Boundaries в React: препарируем лягушку
Представим, что у нас есть приложение на React, в котором можно читать и писать отзывы. Пользователь открыл список отзывов, пролистал его, нажал кнопку «Написать отзыв». Форма написания отзыва открывается в попапе, над списком. Пользователь начинает вводить текст, свой e-mail. Вдруг валидация почты срабатывает с ошибкой, которую разработчики забыли обработать. Результат — белый экран. React просто не смог ничего отрендерить из-за этой ошибки в каком-то попапе. Далее
✍️ @React_lib
Представим, что у нас есть приложение на React, в котором можно читать и писать отзывы. Пользователь открыл список отзывов, пролистал его, нажал кнопку «Написать отзыв». Форма написания отзыва открывается в попапе, над списком. Пользователь начинает вводить текст, свой e-mail. Вдруг валидация почты срабатывает с ошибкой, которую разработчики забыли обработать. Результат — белый экран. React просто не смог ничего отрендерить из-за этой ошибки в каком-то попапе. Далее
✍️ @React_lib
This media is not supported in your browser
VIEW IN TELEGRAM
Руководство - шпаргалка по рендерингу React
Когда происходит повторный рендеринг компонента react? Что может вызвать повторный рендеринг, и как предотвратить ненужный рендеринг? Вот краткая шпаргалка, к которой вы можете обратиться каждый раз, когда будете задавать себе эти вопросы.
https://alexsidorenko.com/blog/react-render-cheat-sheet/
✍️ @React_lib
Когда происходит повторный рендеринг компонента react? Что может вызвать повторный рендеринг, и как предотвратить ненужный рендеринг? Вот краткая шпаргалка, к которой вы можете обратиться каждый раз, когда будете задавать себе эти вопросы.
https://alexsidorenko.com/blog/react-render-cheat-sheet/
✍️ @React_lib
Распространенные ошибки при использовании React Testing Library.
https://te.legra.ph/Rasprostranennye-oshibki-pri-ispolzovanii-React-Testing-Library-06-29
✍️ @React_lib
https://te.legra.ph/Rasprostranennye-oshibki-pri-ispolzovanii-React-Testing-Library-06-29
✍️ @React_lib
Хуки react-router
Используя библиотеку react-router для получения текущего состояния роутера и выполнения навигации, можно использовать кастомные хуки, которые входят в react-router-dom:
- useHistory. Возвращает объект history, который позволяет изменить состояние роутера. Например, можно перенаправить пользователя на другой URL, либо вернуться на предыдущую страницу.
- useLocation. Возвращает объект location, представляющий текущий URL. Этот хук аналогичен useState, который возвращает новый объект location при смене текущего URL.
- useParams. Хук для доступа к параметрам URL, который установлен в роуте.
- useRouteMatch. Этот хук пытается сопоставить текущий URL таким же образом, как и <Route>. Может использоваться взамен компонента <Route>, если необходимо отрендерить что-то при заданном URL.
- useQuery. Хук не входит в список стандартных, но его можно реализовать используя useLocation.
https://reactrouter.com/web/api/Hooks
✍️ @React_lib
Используя библиотеку react-router для получения текущего состояния роутера и выполнения навигации, можно использовать кастомные хуки, которые входят в react-router-dom:
- useHistory. Возвращает объект history, который позволяет изменить состояние роутера. Например, можно перенаправить пользователя на другой URL, либо вернуться на предыдущую страницу.
- useLocation. Возвращает объект location, представляющий текущий URL. Этот хук аналогичен useState, который возвращает новый объект location при смене текущего URL.
- useParams. Хук для доступа к параметрам URL, который установлен в роуте.
- useRouteMatch. Этот хук пытается сопоставить текущий URL таким же образом, как и <Route>. Может использоваться взамен компонента <Route>, если необходимо отрендерить что-то при заданном URL.
- useQuery. Хук не входит в список стандартных, но его можно реализовать используя useLocation.
https://reactrouter.com/web/api/Hooks
✍️ @React_lib
ReactRouterWebsite
React Router: Declarative Routing for React
Learn once, Route Anywhere
Организация react-компонентов с помощью dot-notation и почему я часто прибегаю именно к этому способу
Компонентный подход является основополагающим при создании приложений с помощью react. Компоненты - это главные строительные блоки, которые в своей композиции помогают реализовать сложные системы. В основе каждого компонента, в идеале, всегда лежит какой-то обособленный набор функционала, своего рода микро-решение микро-задачи. Далее
✍️ @React_lib
Компонентный подход является основополагающим при создании приложений с помощью react. Компоненты - это главные строительные блоки, которые в своей композиции помогают реализовать сложные системы. В основе каждого компонента, в идеале, всегда лежит какой-то обособленный набор функционала, своего рода микро-решение микро-задачи. Далее
✍️ @React_lib
Хабр
Организация react-компонентов с помощью dot-notation и почему я часто прибегаю именно к этому способу
Компонентный подход является основополагающим при создании приложений с помощью react. Компоненты - это главные строительные блоки, которые в своей композиции помогают реализовать сложные системы. В...
Кастомный React рендерер
Когда React рендерит приложение и обновляет DOM, то используется React DOM. При рендере приложения на сервере используется модуль
Таким образом, для каждого окружения используется свой рендерер, хотя модуль
Модуль
Для разработки своего рендерера необходимо описать объект “host config”, в котором описаны методы реализации API React. Выглядит так:
https://github.com/facebook/react/blob/main/packages/react-reconciler/README.md
✍️ @React_lib
Когда React рендерит приложение и обновляет DOM, то используется React DOM. При рендере приложения на сервере используется модуль
react-dom/server
. Для мобильных приложений для рендера используется модуль react-native
. Таким образом, для каждого окружения используется свой рендерер, хотя модуль
react
используется везде один. Модуль
react
предоставляет API для определения компонентов, а реализация находится в “рендерерах”. Для связи хуков с реализацией используется объект “диспатчер”. При вызове useState, вызов перенаправляется текущему диспатчеру рендерера. Об этом есть подробная статья в блоге Дэна Абрамова.Для разработки своего рендерера необходимо описать объект “host config”, в котором описаны методы реализации API React. Выглядит так:
const HostConfig = {
createInstance(type, props) {
// e.g. DOM renderer returns a DOM node
},
// ...
supportsMutation: true, // it works by mutating nodes
appendChild(parent, child) {
// e.g. DOM renderer would call .appendChild() here
},
// ...
};
https://github.com/facebook/react/blob/main/packages/react-reconciler/README.md
✍️ @React_lib