Новый текстовый редактор для React – Lexical
Lexical – это новая библиотека для создания текстового редактора с упором на надежность, доступность и производительность. Ядро библиотеки весит всего 22КБ, а нужные плагины для работы редактора можно загружать через lazy load по мере их использования пользователем.
Библиотека не привязана к какому-то конкретному фреймворку и даже к платформе. В планах есть реализация API для iOS. В первую очередь был выбран web и есть официальные биндинги для React.
Внутреннее состояние редактора представляет из себя дерево узлов и объект выбора. Узлы представляют собой основную концепцию в Lexical. Они не только нужны для рендера, но также представляют базовую модель данных для хранения в редакторе для истории. Узлы в редакторе расширяемы, и на основе существующих можно создавать свои кастомные узлы.
Пример компонента:
https://lexical.dev/
Lexical – это новая библиотека для создания текстового редактора с упором на надежность, доступность и производительность. Ядро библиотеки весит всего 22КБ, а нужные плагины для работы редактора можно загружать через lazy load по мере их использования пользователем.
Библиотека не привязана к какому-то конкретному фреймворку и даже к платформе. В планах есть реализация API для iOS. В первую очередь был выбран web и есть официальные биндинги для React.
Внутреннее состояние редактора представляет из себя дерево узлов и объект выбора. Узлы представляют собой основную концепцию в Lexical. Они не только нужны для рендера, но также представляют базовую модель данных для хранения в редакторе для истории. Узлы в редакторе расширяемы, и на основе существующих можно создавать свои кастомные узлы.
Пример компонента:
const editorConfig = {
// The editor theme
theme: ExampleTheme,
// Handling of errors during update
onError(error) {
throw error;
},
// Any custom nodes go here
nodes: [
HeadingNode,
ListNode,
ListItemNode,
QuoteNode,
CodeNode,
CodeHighlightNode,
TableNode,
TableCellNode,
TableRowNode,
AutoLinkNode,
LinkNode
]
};
export default function Editor() {
return (
<LexicalComposer initialConfig={editorConfig}>
<div className="editor-container">
<ToolbarPlugin />
<div className="editor-inner">
<RichTextPlugin
contentEditable={<ContentEditable className="editor-input" />}
placeholder={<Placeholder />}
/>
<HistoryPlugin />
<TreeViewPlugin />
<AutoFocusPlugin />
<CodeHighlightPlugin />
<ListPlugin />
<LinkPlugin />
<AutoLinkPlugin />
<ListMaxIndentLevelPlugin maxDepth={7} />
<LexicalMarkdownShortcutPlugin />
</div>
</div>
</LexicalComposer>
);
}
https://lexical.dev/
🔥6👍1
Хуки, зависимости и устаревшие замыкания
Замыкание очень часто используется в функциональных компонентах, когда внутри компонента объявляется функция и в ней используются пропсы компонента:
Замыкание- это когда функция может взаимодействовать с окружающими переменными. Само замыкание создается каждый раз, когда создается функция, в момент создания функции.
В функциональных компонентах замыкание работает как надо, при каждом рендере компонента объявленные внутри компонента функции создаются заново и получают в свое окружение новые пропсы.
Чаще всего это не вызывает никаких проблем, однако, если понадобится мемоизация функции, то нужно будет оборачивать функцию в useCallback.
При работе с хуками рекомендуется использовать линтер
https://tkdodo.eu/blog/hooks-dependencies-and-stale-closures
Замыкание очень часто используется в функциональных компонентах, когда внутри компонента объявляется функция и в ней используются пропсы компонента:
function Counter({ count }) {
const logCount = () => {
// переменной count берется из внешнего окружения
console.log('count', count)
}
return <button onClick={logCount}>Show me the count</button>
}
Замыкание- это когда функция может взаимодействовать с окружающими переменными. Само замыкание создается каждый раз, когда создается функция, в момент создания функции.
В функциональных компонентах замыкание работает как надо, при каждом рендере компонента объявленные внутри компонента функции создаются заново и получают в свое окружение новые пропсы.
Чаще всего это не вызывает никаких проблем, однако, если понадобится мемоизация функции, то нужно будет оборачивать функцию в useCallback.
При работе с хуками рекомендуется использовать линтер
react-hooks/exhaustive-deps, который подсвечивает неопределенные зависимости для хука useCallback. Если игнорировать список зависимостей useCallback, то используемые внутри него переменные компонента будут устаревшими. https://tkdodo.eu/blog/hooks-dependencies-and-stale-closures
tkdodo.eu
Hooks, Dependencies and Stale Closures
Let's demystify what stale closures are in combination with react hooks with the help of the analogy of taking a photo ...
👍7
HolyJS — конференция для JavaScript-разработчиков от JUG Ru Group, в формате online+offline
Online-часть: 8–10 июня.
Offline-день: 23 июня.
В online вас ждут выступления, посвященные трендам и новым технологиям, обмен опытом и общение в чатах.
На offline-дне в Санкт-Петербурге можно вживую послушать спикеров, лично познакомиться с коллегами и потусоваться у стендов партнеров.
В программе:
– Каким бывает легаси во фронтенде, как с ним справляться и не допускать его появления.
– Что такое proposal Wasm GC, почему его так долго делают и какой путь прошли движки за 2 года экспериментов.
– Как построить дизайн-систему для продукта с 20-миллионной аудиторией, огромной кодовой базой и массой поверхностей.
– Что такое сложность для человеческого мозга и как эти знания помогают писать более понятный код.
Для подписчиков канала организаторы сделали промокод, который поможет вам купить персональный билет со скидкой:
Билеты, подробности и первая программа— на сайте.
Online-часть: 8–10 июня.
Offline-день: 23 июня.
В online вас ждут выступления, посвященные трендам и новым технологиям, обмен опытом и общение в чатах.
На offline-дне в Санкт-Петербурге можно вживую послушать спикеров, лично познакомиться с коллегами и потусоваться у стендов партнеров.
В программе:
– Каким бывает легаси во фронтенде, как с ним справляться и не допускать его появления.
– Что такое proposal Wasm GC, почему его так долго делают и какой путь прошли движки за 2 года экспериментов.
– Как построить дизайн-систему для продукта с 20-миллионной аудиторией, огромной кодовой базой и массой поверхностей.
– Что такое сложность для человеческого мозга и как эти знания помогают писать более понятный код.
Для подписчиков канала организаторы сделали промокод, который поможет вам купить персональный билет со скидкой:
reactnotes2022JRGpcБилеты, подробности и первая программа— на сайте.
👍3❤1
Вышло обновление React 18.1
Спустя месяц после релиза вышло минорное обновление React 18.1.
Среди основных изменений:
- тег <noscript> больше не ругается на react-dom/client
- renderToPipeableStream стал в ~20 раз быстрее
- исправлено двойное срабатывание componentWillUnmount в Suspense
- исправлена ошибка бесконечного ререндера компонента в useDeferredValue
- исправлены различные ошибки гидратации
https://github.com/facebook/react/blob/main/CHANGELOG.md#1810-april-26-2022
Спустя месяц после релиза вышло минорное обновление React 18.1.
Среди основных изменений:
- тег <noscript> больше не ругается на react-dom/client
- renderToPipeableStream стал в ~20 раз быстрее
- исправлено двойное срабатывание componentWillUnmount в Suspense
- исправлена ошибка бесконечного ререндера компонента в useDeferredValue
- исправлены различные ошибки гидратации
https://github.com/facebook/react/blob/main/CHANGELOG.md#1810-april-26-2022
GitHub
react/CHANGELOG.md at main · facebook/react
The library for web and native user interfaces. Contribute to facebook/react development by creating an account on GitHub.
🔥15
Как работает Virtual DOM в React
Как мы знаем, DOM- это древовидная структура, которая используется для отображения элементов на странице. Работа напрямую с DOM может быть достаточно дорогостоящим процессом, т.к. операции с DOM выполняются медленно. React работает не напрямую с браузерным DOM, а через Virtual DOM.
Virtual DOM – это древовидная структура объектов, которая хранится в памяти браузера и хранит элементы страницы. Задача Virtual DOM – определить, что изменилось с точки зрения содержимого элементов или структуры страницы и закоммитить все изменения в реальный DOM.
По своей сути Virtual DOM – это древовидная структура объектов FiberNode (а в целом это FiberTree). FiberNode представляет собой React элемент.
Компонент выше содержит четыре FiberNode: App, <article>, <h2>, <p>. Каждый FiberNode содержит ссылки на соседние FiberNode, родительский и дочерний. Рассмотрим основные свойства FiberNode, сопоставив их значения с примером выше:
-
-
-
В процессе рендера для того, чтобы узнать о необходимых изменениях, в каждом FiberNode есть свойство
https://indepth.dev/posts/1501/exploring-how-virtual-dom-is-implemented-in-react
Как мы знаем, DOM- это древовидная структура, которая используется для отображения элементов на странице. Работа напрямую с DOM может быть достаточно дорогостоящим процессом, т.к. операции с DOM выполняются медленно. React работает не напрямую с браузерным DOM, а через Virtual DOM.
Virtual DOM – это древовидная структура объектов, которая хранится в памяти браузера и хранит элементы страницы. Задача Virtual DOM – определить, что изменилось с точки зрения содержимого элементов или структуры страницы и закоммитить все изменения в реальный DOM.
По своей сути Virtual DOM – это древовидная структура объектов FiberNode (а в целом это FiberTree). FiberNode представляет собой React элемент.
function App () {
return (
<article>
<h2>Title</h2>
<p>Some content</p>
</article>
)
}
Компонент выше содержит четыре FiberNode: App, <article>, <h2>, <p>. Каждый FiberNode содержит ссылки на соседние FiberNode, родительский и дочерний. Рассмотрим основные свойства FiberNode, сопоставив их значения с примером выше:
-
child - дочерний элемент. AppFiberNode.child === ArticleFiberNode-
sibling - соседний элемент. H2FiberNode.sibling === PFiberNode-
return - родительский элемент. H2FiberNode.return === ArticleFiberNodeВ процессе рендера для того, чтобы узнать о необходимых изменениях, в каждом FiberNode есть свойство
alternate. В нем хранится ссылка на копию текущего FiberNode, который был закоммичен в DOM. В процессе рендера происходит сравнение текущего FiberNode и его копии в alternate, и, если они отличаются, то происходит коммит изменений. https://indepth.dev/posts/1501/exploring-how-virtual-dom-is-implemented-in-react
👍6❤2
RFC useEvent
В React RFC появилось новое предложение от Дэна Абрамова – добавить хук
Код внутри
При использовании
Этот хук похож на
RFC https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md
Обсуждение https://github.com/reactjs/rfcs/pull/220
В React RFC появилось новое предложение от Дэна Абрамова – добавить хук
useEvent. Этот хук будет предназначен для использования в обработчиках событий.
function Chat() {
const [text, setText] = useState('');
const onClick = useEvent(() => {
sendMessage(text);
});
return <SendButton onClick={onClick} />;
}
Код внутри
useEvent будет иметь доступ к актуальным значениям пропсов/стейтов в момент вызова. Возвращаемая функция будет иметь одинаковую ссылку, даже если пропсы/стейты, на которые она ссылается, изменились. Также в useEvent не будет массива зависимостей. При использовании
useEffect можно будет исключить из списка зависимостей функции, объявленные через useEvent. Таким образом, эффекты не будут перезапускаться при изменении ссылки на обработчики событий.
function Page({ route, currentUser }) {
// ✅ Stable identity
const onVisit = useEvent(visitedUrl => {
logAnalytics('visit_page', visitedUrl, currentUser.name);
});
useEffect(() => {
onVisit(route.url);
}, [route.url]); // ✅ Re-runs only on route change
// ...
}
Этот хук похож на
useCallback, только без массива зависимостей. Однако, есть ограничения на его использование. Например, его нельзя использовать для рендеринга компонентов (т.е. возвращать JSX).RFC https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md
Обсуждение https://github.com/reactjs/rfcs/pull/220
GitHub
rfcs/text/0000-useevent.md at useevent · reactjs/rfcs
RFCs for changes to React. Contribute to reactjs/rfcs development by creating an account on GitHub.
👍15
Использование пропа key в React для эффективного рендера
В документации React для лучшей производительности списков советуют использовать в качестве key уникальный id элемента. Но что будет, если использовать в качестве key текущий индекс элемента?
Чтобы разобраться с этим, давайте изучим, как работает проп key. Если обобщенно, то он используется для идентификации элементов одного типа в списке при ререндере элементов.
Например, есть два списка элементов:
В качестве триггера для ререндера будет использоваться кнопка, которая меняет сортировку элементов.
В случае, когда в key используется текущий индекс, при ререндере списка у первого элемента всегда будет key = 0. React считает элементы одинаковыми, если у них одинаковый key. Поэтому при использовании в качестве key текущий индекс массива, элементы списка всегда будут считаться одинаковыми. Но проп country у элементов будет другой, поэтому будет происходить ререндер мемоизированного компонента.
Для списка, где в key используется id, при ререндере элементов React идентифицирует одинаковые элементы и не происходит ререндера элементов.
https://www.developerway.com/posts/react-key-attribute
В документации React для лучшей производительности списков советуют использовать в качестве key уникальный id элемента. Но что будет, если использовать в качестве key текущий индекс элемента?
Чтобы разобраться с этим, давайте изучим, как работает проп key. Если обобщенно, то он используется для идентификации элементов одного типа в списке при ререндере элементов.
Например, есть два списка элементов:
const ItemMemo = React.memo(Item);
const CountriesList = ({ countries }) => {
const [sort, setSort] = useState('asc');
const sortedCountries = orderBy(countries, 'name', sort);
const button = <button onClick={() => setSort(sort === 'asc' ? 'desc' : 'asc')}>toggle sorting: {sort}</button>;
return (
<div>
{button}
{sortedCountries.map((country) => (
<ItemMemo country={country} key={country.id} />
))}
{sortedCountries.map((country, index) => (
<ItemMemo country={country} key={index} />
))}
</div>
);
};
В качестве триггера для ререндера будет использоваться кнопка, которая меняет сортировку элементов.
В случае, когда в key используется текущий индекс, при ререндере списка у первого элемента всегда будет key = 0. React считает элементы одинаковыми, если у них одинаковый key. Поэтому при использовании в качестве key текущий индекс массива, элементы списка всегда будут считаться одинаковыми. Но проп country у элементов будет другой, поэтому будет происходить ререндер мемоизированного компонента.
Для списка, где в key используется id, при ререндере элементов React идентифицирует одинаковые элементы и не происходит ререндера элементов.
https://www.developerway.com/posts/react-key-attribute
Developerway
React key attribute: best practices for performant lists
Looking into how React "key" attribute works, how to use it correctly, how to improve performance of lists with it, and why array index as key is a good idea sometimes
👍8
React для создания видео
Remotion – инструмент для создания видео на React. Зачем нужно создавать видео, используя React?
- Используйте веб-технологии: CSS, WebGL, Canvas и т.д.
- Используйте программирование: переменные, функции, API и различные алгоритмы.
- Используйте React: переиспользование компонентов, композиция.
Remotion – это как After Effects, но для программистов. Если в After Effects потребуется переиспользовать какой-то элемент в нескольких местах, то придется копировать его в ручную. В Remotion используется React, где хорошо работает композиция и можно легко переиспользовать любой элемент.
Один из плюсов данного инструмента в том, что можно создавать видео на лету, кастомизируя его содержимое. Например, используя данные из API создавать индивидуальное видео для каждого пользователя.
Основная идея Remotion в том, что компонент получает текущий фрейм видео. Компонент что-то рендерит, Remotion это записывает и создаёт видео. Для создания скриншота рендера фрейма используется Puppeteer, запускаемый в параллельном режиме. Для склейки скриншотов и создания видео используется FFMPeg.
https://www.remotion.dev/
Интервью с мейнтенером https://www.learnwithjason.dev/make-video-with-code
Remotion – инструмент для создания видео на React. Зачем нужно создавать видео, используя React?
- Используйте веб-технологии: CSS, WebGL, Canvas и т.д.
- Используйте программирование: переменные, функции, API и различные алгоритмы.
- Используйте React: переиспользование компонентов, композиция.
Remotion – это как After Effects, но для программистов. Если в After Effects потребуется переиспользовать какой-то элемент в нескольких местах, то придется копировать его в ручную. В Remotion используется React, где хорошо работает композиция и можно легко переиспользовать любой элемент.
Один из плюсов данного инструмента в том, что можно создавать видео на лету, кастомизируя его содержимое. Например, используя данные из API создавать индивидуальное видео для каждого пользователя.
Основная идея Remotion в том, что компонент получает текущий фрейм видео. Компонент что-то рендерит, Remotion это записывает и создаёт видео. Для создания скриншота рендера фрейма используется Puppeteer, запускаемый в параллельном режиме. Для склейки скриншотов и создания видео используется FFMPeg.
import {interpolate, useCurrentFrame} from 'remotion'
const Title: React.FC<{noscript: string}> = ({noscript}) => {
const frame = useCurrentFrame()
const opacity = interpolate(frame, [0, 20], [0, 1], {extrapolateRight: 'clamp'})
return (
<div style={{opacity}}>{noscript}</div>
)
}
export const MyVideo = () => {
return (
<div style={{ textAlign: "center" }}>
<Title noscript="Hello World" />
</div>
);
};
https://www.remotion.dev/
Интервью с мейнтенером https://www.learnwithjason.dev/make-video-with-code
www.remotion.dev
Remotion | Make videos programmatically
👍6
Как работает поверхностное сравнение в React
Поверхностное сравнение используется в React в качестве механизма для определения необходимости обновления компонента, массива зависимостей хука, изменения пропсов мемоизированного компонента. Давайте рассмотрим функцию поверхностного сравнения и разберемся как она работает.
Выводы:
- Для сравнения объектов используется
- В поверхностном сравнение пустой массив и пустой объект равны.
- Объект с индексами в ключах и массив с такими же значениями одинаковы, т.е. { 0: 2, 1: 3 } равен [2, 3].
- Из-за использования
https://www.chakshunyu.com/blog/how-does-shallow-comparison-work-in-react/
Поверхностное сравнение используется в React в качестве механизма для определения необходимости обновления компонента, массива зависимостей хука, изменения пропсов мемоизированного компонента. Давайте рассмотрим функцию поверхностного сравнения и разберемся как она работает.
import is from './objectIs';
import hasOwnProperty from './hasOwnProperty';
function shallowEqual(objA: mixed, objB: mixed): boolean {
/**
* Проверка равенства примитивных значений.
*/
if (is(objA, objB)) {
return true;
}
/**
* Проверка на то, что текущие аргументы являются объектами и не равны null.
*/
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false;
}
/**
* На этом шаге мы уверены что работаем с объектами, получаем ключи объекта.
*/
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
/**
* Сравниваем количество ключей объектов.
*/
if (keysA.length !== keysB.length) {
return false;
}
/**
* Сравнение значения объекта для каждого ключа объекта A с объектом B.
* Проверяется наличие ключа объекта A в объекте B.
*/
for (let i = 0; i < keysA.length; i++) {
const currentKey = keysA[i];
if (
!hasOwnProperty.call(objB, currentKey) ||
!is(objA[currentKey], objB[currentKey])
) {
return false;
}
}
return true;
}
Выводы:
- Для сравнения объектов используется
Object.is вместо строгого равенства.- В поверхностном сравнение пустой массив и пустой объект равны.
- Объект с индексами в ключах и массив с такими же значениями одинаковы, т.е. { 0: 2, 1: 3 } равен [2, 3].
- Из-за использования
Object.is вместо ===, +0 и -0 не равны, а Number.NaN и NaN равны. https://www.chakshunyu.com/blog/how-does-shallow-comparison-work-in-react/
Chakshunyu
How Does Shallow Comparison Work In React?
Shallow comparison is a concept all over React development and documentation. It plays a key role in React’s internals, but it’s not often explained. This article covers how it works by diving into the source code and finishes with some interesting takeaways.
👍4
useTilg – хук для отладки компонентов
Tiny Logger – небольшой хук для отладки компонентов. Выводит информацию, когда компонент был отрендерен (с какими пропсами), смонтирован и размонтирован. Также хук позволяет отследить как изменились стейты при рендере.
https://github.com/shuding/tilg
Tiny Logger – небольшой хук для отладки компонентов. Выводит информацию, когда компонент был отрендерен (с какими пропсами), смонтирован и размонтирован. Также хук позволяет отследить как изменились стейты при рендере.
import { useState } from 'react'
import useTilg from 'tilg'
function MyApp() {
const [input, setInput] = useState('')
const [count, setCount] = useState(0)
useTilg()`input = ${input}, count = ${count}`
return (
<>
<input onChange={(e) => setInput(e.target.value)} value={input} />
<button onClick={() => setCount(count + 1)}>{count}</button>
</>
)
}
https://github.com/shuding/tilg
👍10👎2
Почему нельзя вызывать хуки по условию
Например, компонент по определенному условию вернул null. Это невалидный код на React. Но почему так делать нельзя?
В первую очередь стоит помнить, что babel компилирует код JSX в обычные функции createElement:
React рендерит компоненты, вызывает createElement, создает Virtual DOM и выводит пользователю в браузер отрендеренные элементы. Рендер – это просто вызов функции функционального компонента. Функциональный компонент вызывается, возвращается вызов createElement, React сравнивает текущее и новое дерево VDOM и коммитит изменения в DOM.
Важно понимать, что функциональный компонент это функция, которую вызывает React. Это создает проблему: как сохранить данные в стейте при вызовах функции (рендере). Например, следующий код при каждом вызове будет писать в консоль “1”:
Для того чтобы сохранять состояние стейта между рендерами компонента, React сохраняет состояние во внешнем объекте по ID хука, примерно так:
Вот почему мы не можем условно отображать хуки: они отслеживаются на основе порядка вызовов, используя в качестве ID счетчик.
Более подробно про хуки написано в блоке Дэна Абрамова: https://overreacted.io/why-do-hooks-rely-on-call-order/
Например, компонент по определенному условию вернул null. Это невалидный код на React. Но почему так делать нельзя?
const ConditionalComponent = (props) => {
if (!props.visible) return null;
const [value, setValue] = useState();
}
В первую очередь стоит помнить, что babel компилирует код JSX в обычные функции createElement:
const MyComponent = () => {
return <div>Hello world</div>
}
// babel компилирует в
const MyComponent = () => {
return React.createElement("div", null, "Hello world");
};
React рендерит компоненты, вызывает createElement, создает Virtual DOM и выводит пользователю в браузер отрендеренные элементы. Рендер – это просто вызов функции функционального компонента. Функциональный компонент вызывается, возвращается вызов createElement, React сравнивает текущее и новое дерево VDOM и коммитит изменения в DOM.
Важно понимать, что функциональный компонент это функция, которую вызывает React. Это создает проблему: как сохранить данные в стейте при вызовах функции (рендере). Например, следующий код при каждом вызове будет писать в консоль “1”:
const Test = () => {
let a = 1;
console.log(a);
a++;
}
Test(); // 1
Test(); // 1
Test(); // 1
Для того чтобы сохранять состояние стейта между рендерами компонента, React сохраняет состояние во внешнем объекте по ID хука, примерно так:
const state = [];
// Уникальный ID хука, счетчик
let idx = 0;
function useState(init) {
state[idx] = state[idx] ?? { val: init };
return [
state[idx].val,
data => state[idx].val = data
]
}
function Test() {
const [name, setName] = useState('React');
}
Вот почему мы не можем условно отображать хуки: они отслеживаются на основе порядка вызовов, используя в качестве ID счетчик.
Более подробно про хуки написано в блоке Дэна Абрамова: https://overreacted.io/why-do-hooks-rely-on-call-order/
overreacted.io
Why Do React Hooks Rely on Call Order? — overreacted
Lessons learned from mixins, render props, HOCs, and classes.
👍7
RFC шаблонов в Next.js
Next.js планирует изменить свою систему роутинга. Это поможет адаптировать фичи React 18 и другие новые фичи.
Добавятся новые конвенции именования. Папка
Появится поддержка вложенных роутов/шаблонов с использованием компонента
Также при использовании Suspense будет улучшение в загрузки данных. Вместо последовательной загрузки роутов и данных будет происходит их параллельная загрузка.
https://nextjs.org/blog/layouts-rfc
Next.js планирует изменить свою систему роутинга. Это поможет адаптировать фичи React 18 и другие новые фичи.
Добавятся новые конвенции именования. Папка
./pages останется, но появится папка ./app, в которой будут работать новые фичи, например, Server Components. Появится поддержка вложенных роутов/шаблонов с использованием компонента
layout.js. Также появится компонент page.js, который будет использоваться для отображения страницы роута.Также при использовании Suspense будет улучшение в загрузки данных. Вместо последовательной загрузки роутов и данных будет происходит их параллельная загрузка.
https://nextjs.org/blog/layouts-rfc
nextjs.org
Layouts RFC
Nested routes and layouts, client and server routing, React 18 features, and designed for Server Components.
👍4🔥3
Мигрируем с Jest на Vitest
Vitest – это фреймворк тестирования, использующий в качестве сборщика Vite.js. Vitest использует совместимый с Jest API и поддерживает из под коробки основные фичи для тестирования (моки, снапшоты, покрытие). Также фреймворк поддерживает многопоточность, используя библиотеку tinypool.
Vitest особенно актуален, если вы используете в качестве сборщика приложения Vite.js. В этом случае для запуска тестов и сборки приложения будет использоваться один и тот же конфиг приложения (vite.config.js).
Если вы используете Jest, то совсем не сложно перейти на Vitest, учитывая что их API похоже. Катал Мак Доннача описал шаги для миграции с Jest на Vitest:
https://cathalmacdonnacha.com/migrating-from-jest-to-vitest
Vitest – это фреймворк тестирования, использующий в качестве сборщика Vite.js. Vitest использует совместимый с Jest API и поддерживает из под коробки основные фичи для тестирования (моки, снапшоты, покрытие). Также фреймворк поддерживает многопоточность, используя библиотеку tinypool.
Vitest особенно актуален, если вы используете в качестве сборщика приложения Vite.js. В этом случае для запуска тестов и сборки приложения будет использоваться один и тот же конфиг приложения (vite.config.js).
Если вы используете Jest, то совсем не сложно перейти на Vitest, учитывая что их API похоже. Катал Мак Доннача описал шаги для миграции с Jest на Vitest:
https://cathalmacdonnacha.com/migrating-from-jest-to-vitest
Everyday Frontend 🚀
Migrating from Jest to Vitest
I recently migrated from create-react-app (CRA) to ViteJS, and as part of that, I switched my test runner from Jest to Vitest.
In this article, I go through all the steps I took as part of the migration, in the hope that it might help others who are ...
In this article, I go through all the steps I took as part of the migration, in the hope that it might help others who are ...
👍3👎1
Обзор библиотек управления состоянием
Библиотеки управления состоянием определяют, как приложение будет делиться своим состоянием. Оно может быть глобальным или локальным для определенного участка приложения.
Менеджеры состояний позволяют избавиться от проп-дриллинга, когда компоненты создают пропсы, чтобы передать их в дочерние компоненты.
Альберт Гао в своем блоге составил обзор популярных библиотек управления состоянием. Библиотеки разбиты на категории: по структуре сторов (глобальный, несколько или атомарный), способу чтения записей из стора (селектор или геттер) и способу обновления стора (React-подобный API, экшен объект или инкапсулированный метод стора).
https://www.albertgao.xyz/2022/02/19/react-state-management-libraries-2022/
Библиотеки управления состоянием определяют, как приложение будет делиться своим состоянием. Оно может быть глобальным или локальным для определенного участка приложения.
Менеджеры состояний позволяют избавиться от проп-дриллинга, когда компоненты создают пропсы, чтобы передать их в дочерние компоненты.
Альберт Гао в своем блоге составил обзор популярных библиотек управления состоянием. Библиотеки разбиты на категории: по структуре сторов (глобальный, несколько или атомарный), способу чтения записей из стора (селектор или геттер) и способу обновления стора (React-подобный API, экшен объект или инкапсулированный метод стора).
https://www.albertgao.xyz/2022/02/19/react-state-management-libraries-2022/
Through the binary
React state management libraries in 2022
The React state management library is a constant topic in React community, but seems we are pretty settled recently with some obvious winners. This blog will focus all the popular choices and compare
👍5❤1
Обновление React Router v6.4.0-pre
В новую минорную версию React Router v6.4 было добавлено много новых абстракций из Remix: action, loader.
Если для страницы будут нужны данные, то их можно вернуть в функции loader, а получить в самом компоненте через хук useLoaderData. Функция action используется для мутаций. Мутации выполняются через отправку формы, используя компонент Form, или через хук useSubmit.
https://beta.reactrouter.com/en/remixing/getting-started/data
В новую минорную версию React Router v6.4 было добавлено много новых абстракций из Remix: action, loader.
Если для страницы будут нужны данные, то их можно вернуть в функции loader, а получить в самом компоненте через хук useLoaderData. Функция action используется для мутаций. Мутации выполняются через отправку формы, используя компонент Form, или через хук useSubmit.
export async function loader({ params }) {
const note = await getNote(params.noteId);
if (!note) throw new Response("", { status: 404 });
return note;
}
export async function action({ params }) {
await deleteNote(params.noteId);
return redirect("/new");
}
export default function Note() {
const note = useLoaderData();
return (
<div>
<h2>{note.noscript}</h2>
<div>{note.content}</div>
<Form method="post">
<button type="submit">Delete</button>
</Form>
</div>
);
}
createRoot(document.getElementById("root")).render(
<DataBrowserRouter>
<Route path="/" element={<Root />} loader={rootLoader}>
<Route
path="note/:noteId"
element={<Note />}
loader={noteLoader}
action={noteAction}
errorElement={<div>Note not found</div>}
/>
</Route>
</DataBrowserRouter>
);
https://beta.reactrouter.com/en/remixing/getting-started/data
❤2🔥2👎1
HolyJS 2022 Spring пройдет уже через неделю. 8–10 июня, на 80% online, а 23 июня в Санкт-Петербурге будет offline-день.
Вас ждут 24 доклада от разработчиков из VK, Яндекса, QIWI, Тинькофф и других компаний. Поговорим о фреймворках, перформансе, техническом долге, архитектуре, работе с Node.js, serverless-подходе, графике, TypeScript и wasm.
Среди докладов:
✔ «Безопасность данных: построение архитектуры при интеграции алгоритмов шифрования в приложении для финансового учета»;
✔ «Wasm GC»;
✔ «TypeScript: компромиссы проектирования языка»;
✔ «Поймать дзен, работая над дизайн-системой Яндекс.Дзена»;
✔ «Serverless — это не страшно!»;
✔ «Нейрофизиология сложности кода».
Подробности и готовая программа — на сайте конференции.
Покупая билет на конференцию из вкладки «для частных лиц» используйте промокод
Вас ждут 24 доклада от разработчиков из VK, Яндекса, QIWI, Тинькофф и других компаний. Поговорим о фреймворках, перформансе, техническом долге, архитектуре, работе с Node.js, serverless-подходе, графике, TypeScript и wasm.
Среди докладов:
✔ «Безопасность данных: построение архитектуры при интеграции алгоритмов шифрования в приложении для финансового учета»;
✔ «Wasm GC»;
✔ «TypeScript: компромиссы проектирования языка»;
✔ «Поймать дзен, работая над дизайн-системой Яндекс.Дзена»;
✔ «Serverless — это не страшно!»;
✔ «Нейрофизиология сложности кода».
Подробности и готовая программа — на сайте конференции.
Покупая билет на конференцию из вкладки «для частных лиц» используйте промокод
reactnotes2022JRGpc для скидки.Создание мини-версии Next.js
Джонас Гальвес в своем блоге рассказал. как создать свою мини-версию фреймворка Next.js. В своем эксперименте автор сосредоточился на двух основных фичах:
- роутинг на основе файлов в папке
- возможность изоморфного получения данных, используя функцию
Для сборки проекта используется Vite. Для получения списка файлов и его экспортов используется метод
https://hire.jonasgalvez.com.br/2022/may/18/building-a-mini-next-js/
Джонас Гальвес в своем блоге рассказал. как создать свою мини-версию фреймворка Next.js. В своем эксперименте автор сосредоточился на двух основных фичах:
- роутинг на основе файлов в папке
/pages;- возможность изоморфного получения данных, используя функцию
getServerSideProps();Для сборки проекта используется Vite. Для получения списка файлов и его экспортов используется метод
import.meta.globEager('/pages/**/*.jsx’), который возвращает массив объектов страниц с экспортами. Роуты формируются автоматически с использованием react-router-dom.https://hire.jonasgalvez.com.br/2022/may/18/building-a-mini-next-js/
hire.jonasgalvez.com.br
Building a Mini Next.js
👍7❤3
Работа с 3D моделями в Three.js
Вводный гайд по работе с 3D моделями с использованием библиотеки react-three-fiber. Разбирается как подключать glTF модели и отображать их на канвасе. Для работы со светом есть компоненты <ambientLight> (заполняет светом всю сцену) и <pointLight> (свет по определенным точкам, как лампа). Для ручного управления камерой мышью используется компонент <OrbitControls>.
https://betterprogramming.pub/working-with-3d-model-in-three-js-e228621141af
Вводный гайд по работе с 3D моделями с использованием библиотеки react-three-fiber. Разбирается как подключать glTF модели и отображать их на канвасе. Для работы со светом есть компоненты <ambientLight> (заполняет светом всю сцену) и <pointLight> (свет по определенным точкам, как лампа). Для ручного управления камерой мышью используется компонент <OrbitControls>.
https://betterprogramming.pub/working-with-3d-model-in-three-js-e228621141af
Medium
Working With 3D Models in Three.js
Exhibit three.js code in the Create React App working environment
👍3
Как работает хук 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
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
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.
👍7
Бесплатный день HolyJS 2022 Spring!
Команде организаторов и Программному комитету HolyJS хотелось бы, чтобы их усилия оценило как можно больше участников. Поэтому доступ к третьему дню конференции будет открыт для всех желающих.
Community Day на HolyJS 2022 Spring — 10 июня доступ свободный
В билет бесплатного дня входят:
✔ 4 доклада: например, про server-driven UI в вебе и преобразование TypeScript в Java.
✔ Воркшоп: спикеры покажут, как написать приложение для конвертации криптовалюты с микросервисной архитектурой с помощью gRPC на платформе Node.js.
✔ Дискуссии после докладов.
✔ Возможность поучаствовать в играх, квизах, конкурсах и других активностях от партнеров конференции — там можно не только круто провести время, но и получить ценные призы.
✔ Чаты, где сидят сотни ваших коллег со всего мира.
Для участия в Community Day нужно только зарегистрироваться — для этого переходите по ссылке.
Команде организаторов и Программному комитету HolyJS хотелось бы, чтобы их усилия оценило как можно больше участников. Поэтому доступ к третьему дню конференции будет открыт для всех желающих.
Community Day на HolyJS 2022 Spring — 10 июня доступ свободный
В билет бесплатного дня входят:
✔ 4 доклада: например, про server-driven UI в вебе и преобразование TypeScript в Java.
✔ Воркшоп: спикеры покажут, как написать приложение для конвертации криптовалюты с микросервисной архитектурой с помощью gRPC на платформе Node.js.
✔ Дискуссии после докладов.
✔ Возможность поучаствовать в играх, квизах, конкурсах и других активностях от партнеров конференции — там можно не только круто провести время, но и получить ценные призы.
✔ Чаты, где сидят сотни ваших коллег со всего мира.
Для участия в Community Day нужно только зарегистрироваться — для этого переходите по ссылке.
Listener API в Redux Toolkit
В RTK с самого начала используется redux-thunk в качестве дефолтного мидлвара для написания синхронной и асинхронной логики вне компонента. Однако, thunk не позволяет вызывать side effect функцию в ответ на dispatch экшена. Для таких целей обычно используется redux-saga.
В redux-toolkit v1.8.0 появилось новое listener API, которое позволяет создавать мидлвар для подписки на экшен или изменении стейта. Концептуально новое API похоже на useEffect, которое запускается в ответ на изменении стора.
Подписка может быть создана как в процессе создания стора через
Обзор и сравнение с redux-saga:
https://blog.logrocket.com/redux-toolkits-new-listener-middleware-vs-redux-saga/
В RTK с самого начала используется redux-thunk в качестве дефолтного мидлвара для написания синхронной и асинхронной логики вне компонента. Однако, thunk не позволяет вызывать side effect функцию в ответ на dispatch экшена. Для таких целей обычно используется redux-saga.
В redux-toolkit v1.8.0 появилось новое listener API, которое позволяет создавать мидлвар для подписки на экшен или изменении стейта. Концептуально новое API похоже на useEffect, которое запускается в ответ на изменении стора.
Подписка может быть создана как в процессе создания стора через
listenerMiddleware.startListening(), либо динамически в рантайме через dispatch(addListener()).
// 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-saga:
https://blog.logrocket.com/redux-toolkits-new-listener-middleware-vs-redux-saga/
LogRocket Blog
Redux Toolkit's new listener middleware vs. Redux-Saga - LogRocket Blog
Redux Toolkit's new listener middleware is a great alternative to Redux Saga, with a few caveats - learn all about it in this complete guide.
👍7