Введение
Это вторая из двух статей (нажмите здесь, чтобы посмотреть первую), посвященных очень популярной JavaScript библиотеке - React. Данная библиотека широко используется в проектах нашей компании. В этой статье мы продолжим рассматривать основные концепты этой библиотеки, чтобы незнакомый с React читатель мог получить представление как устроена работа с ней.

1 Хуки (Hooks)
useState() является примером хука в React, который позволяет использовать такие особенности, как состояние, внутри функциональных компонентов.
Существует пять основных разновидностей хуков:
- Хуки состояния, такие как useState() и useReducer(), помогают управлять состоянием внутри компонентов React.
- Хуки контекста, такие как useContext(), позволяют использовать данные, передаваемые через контекст React.
- Хуки ссылок, такие как useRef(), позволяют ссылаться на такие объекты, как HTML-элементы.
- Хуки эффектов, такие как useEffect(), позволяют взаимодействовать с внешними системами, такими как API браузера.
- Хуки производительности, такие как useMemo() и useCallback(), могут улучшить производительность, предотвращая ненужные операции.
2 Чистота (Purity)
Чистота — это термин, который используется для описания того как должны работать компоненты React. Эту так называемую чистоту можно сравнить с чистотой математических формул.
Чистые компоненты React - это такие компоненты, для которых выполняется условие, что одинаковые входные данные всегда приводят к тому же одинаковому результату, соответствующему этим данным.
Чтобы сохранить компонент React чистым, он должен только возвращать свой JSX и не изменять любые объекты или переменные, которые существовали до рендеринга.
let count = 0
function Cup() {
count = count + 1 //не делайте так
return <h2> Cup {count} </h2>
}
Компонент Cup в этом примере является нечистым, потому что он изменяет переменную count во время рендеринга, которая существует вне компонента.
Это приводит к тому, что jsx выдает неправильный результат, когда используется более одного раза.
3 Режим строгой проверки (Strict Mode)
Чтобы избежать ошибок, подобных упомянутым ранее, мы можем использовать так называемый режим строгой проверки (strict mode). Режим строгой проверки — это специальный компонент, который сообщает нам об ошибках во время разработки наших React-приложений.
Это очень удобно, потому что режим строгой проверки — это просто компонент, который мы обычно оборачиваем вокруг нашего основного компонента приложения, и он подскажет нам, когда действительно не стоит что-то делать.
import { StrictMode } from 'react'
<StrictMode>
<App/>
</StrictMode>
4 Эффекты (Effects)
Но что, если нам нужно сделать что-то вне нашего React-приложения? Приложению может понадобиться взаимодействовать с API браузера или отправить запрос на сервер. Если нужно работать с внешней системой, нам понадобится способ выйти за пределы React.
Эффекты — это код, который выходит за пределы нашего React-приложения. Обычно эффекты, также известные как побочные эффекты (side effects), можно выполнять в обработчиках событий, например, чтобы сделать HTTP-запрос при отправке формы или нажатии кнопки.
function handleSubmit(e) {
e.preventDefault()
post('/api/register', {email, password}) //запрос (побочный эффект), который выполняется в обработчике событий
}
Если вы не можете выполнить эффекты в обработчике событий, вы можете выполнить их с помощью хука useEffect().
useEffect ( () => {
fetchData().then(data => {
//используйте данные здесь
})
}, [])
Один из распространенных паттернов — это получение данных при первой загрузке компонентов с помощью хука useEffect.
5 Ссылки (Refs)
Как и в случае с эффектами, иногда вам нужно выйти за пределы React и работать напрямую с DOM.
Чтобы ссылаться на реальный элемент DOM, вы можете использовать так называемую ссылку (ref).
<Button ref={ref}/> => <button></button>
Вы можете создать ссылку с помощью хука useRef() и получить доступ к элементу DOM, используя свойство ref на любом элементе React.
Для некоторых задач, таких как установка фокуса на элемент ввода, гораздо проще ссылаться на реальный элемент DOM, чем пытаться сделать это в стиле React.
const ref= useRef() // создаем ссылку
<input ref = {ref} /> //добавляем как свойство
ref.current.focus() //используем элемент через .current
6 Контекст (Context)
Контекст — это мощный способ передавать данные (prop data) между компонентами приложения.
Большинство React-приложений содержат множество вложенных компонентов. Чтобы передать данные на несколько уровней вниз, приходится передавать одни и те же props через компоненты, которым они на самом деле не нужны. Контекст позволяет нам перепрыгивать через дерево компонентов и использовать данные на любом уровне, не создавая props.
Чтобы использовать контекст, вы сначала создаете контекст в родительском компоненте, затем оборачиваете родительский компонент в специальный контекстный компонент, называемый провайдером контекста.
Поместите данные, которые вы хотите передать, в провайдер, и, затем, получите доступ к этим данным в любом дочернем компоненте с помощью хука useContext.
//1 - Создайте контекст
const AppContext = createContext()
//2 - Оберните родительский компонент в провайдер контекста:
<AppContext.Provider>
<App/>
</AppContext.Provider>
//3 - Установите значение, которое вы хотите передать, в провайдере:
<AppContext.Provider value="tune-it">
<App />
</AppContext.Provider>
//4 - Получите доступ к данным в дочернем компоненте с помощью хука useContext:
function Title() {
const text = useContext(AppContext)
return <h1> {text} </h1>
}
7 Порталы (Portals)
Порталы позволяют перемещать компоненты React в любой HTML-элемент, который вы выберете. Порталы отлично подходят для компонентов, которые не могут отображаться правильно из-за стилей их родительских компонентов, например, для модальных окон, выпадающих меню и всплывающих подсказок.
Чтобы создать портал, просто используйте функцию createPortal(). Передайте ей ваш компонент и выберите HTML-элемент, в котором вы хотите, чтобы ваш компонент React отображался.
import { createPortal } from 'react-dom';
<div>
<p>Я в родительском div.</p>
{createPortal(
<p>Я в теле документа.</p>,
document.body
)}
</div>
В этом примере первый <p> находится внутри родительского div, а второй <p> находится в теле документа (document body) благодаря использованию портала.
8 Suspense
Suspense — это специальный компонент, который помогает вам управлять загрузкой компонента или его данных.
Пример использования:
<Suspense fallback={<Loading />}>
<Component />
</Suspense>
Suspense полезен для компонентов, которые требуют времени для получения данных. Он улучшает удобство работы с приложением для пользователя, показывая ему запасной компонент, например, индикатор загрузки, пока данные не станут доступны, вместо того чтобы показывать пустое место.
Suspense также полезен, если вы "лениво" загружаете компонент, то есть загружаете его только тогда, когда он действительно нужен.
import { lazy, Suspense } from 'react';
const Component = lazy(() => import('./Component')); // ленивая загрузка компонента
<Suspense fallback={<Loading />}>
<Component /> // загружается только когда он нужен
</Suspense>
9 Границы ошибок (Error Boundaries)
Поскольку приложения React под капотом полностью состоят из JavaScript, ошибки, которые происходят во время рендеринга, могут полностью сломать ваше приложение. Границы ошибок — это компоненты, которые позволяют вам ловить критические ошибки приложения и показывать запасной компонент, чтобы информировать пользователя о произошедшем.
Например, наше приложение упадет, если мы запустим следующий код, так как он выбрасывает ошибку, когда нет данных пользователя:
function App({ user }) {
if (!user) {
throw new Error("No user data");
}
return <h1>{user.name}</h1>;
}
<App /> // ошибка! Данные пользователя не переданы
Чтобы предотвратить падение нашего приложения, сначала добавим границу ошибок, чтобы отображать запасной компонент с более информативным сообщением об ошибке для пользователя.
import { ErrorBoundary } from 'react-error-boundary';
function Fallback({ error }) {
return (
<div role="alert">
<p>Данные пользователя не предоставлены:</p>
<pre>{error.message}</pre>
</div>
);
}
<ErrorBoundary FallbackComponent={Fallback}>
<App />
</ErrorBoundary>
В этом примере, если ошибка будет выброшена внутри компонента App, граница ошибок ErrorBoundary поймает её и отобразит компонент Fallback с сообщением об ошибке вместо того, чтобы приложение полностью упало.
Заключение
Современные веб-приложения, особенно те, которые построены с использованием библиотеки React, требуют понимания и умелого применения различных инструментов и методов для управления состоянием, взаимодействием с DOM, обработкой данных и управления ошибками.
- Хуки (Hooks): позволяют управлять состоянием и эффектами внутри функциональных компонентов, что делает код чище и легче для понимания. Основные хуки, такие как useState(), useEffect(), и useRef(), предоставляют мощные возможности для работы с состоянием, побочными эффектами и DOM-элементами.
- Чистота (Purity): Чистые компоненты React гарантируют, что одинаковые входные данные всегда дают одинаковый результат. Это способствует предсказуемости и упрощает тестирование и отладку.
- Режим строгой проверки (Strict Mode): Этот инструмент помогает выявлять потенциальные проблемы на ранних стадиях разработки, делая процесс создания приложений более "безопасным" и надежным.
- Эффекты (Effects): Побочные эффекты, такие как запросы к API или взаимодействие с внешними системами, управляются с помощью хука useEffect(). Это позволяет четко определять и контролировать моменты, когда приложение взаимодействует с внешним миром.
- Ссылки (Refs): Они позволяют напрямую работать с элементами DOM, что полезно для задач, требующих точного управления элементами.
- Контекст (Context): Контекст облегчает передачу данных через дерево компонентов, избегая необходимости передавать пропсы через множество уровней. Это упрощает код и делает его более читабельным.
- Порталы (Portals): Этот механизм позволяет рендерить компоненты в любом месте DOM, что полезно для таких компонентов, как модальные окна и всплывающие подсказки, которые могут быть ограничены стилями родительских компонентов.
- Suspense: Этот компонент помогает управлять состоянием загрузки данных или компонентов, предоставляя пользователю более плавный и информативный интерфейс в ожидании завершения загрузки.
- Границы ошибок (Error Boundaries): Они позволяют ловить ошибки рендеринга, предотвращая падение всего приложения и предоставляя пользователю полезные сообщения об ошибках.
Вместе эти инструменты и подходы делают разработку с React более эффективной, структурированной и устойчивой к ошибкам. Они позволяют создавать высокопроизводительные и пользовательски-ориентированные приложения, поддерживая высокий уровень качества кода и улучшая процесс разработки.