React.js — один из лучших и наиболее популярных способов создать одностраничное приложение. Это гибкий и удобный фреймворк, с помощью которого можно либо добавить компонент на существующий сайт, либо создать новый сайт с нуля.
Сейчас React.js используется во многих других фреймворках и инструментах вроде Next.js, GatsbyJs, Razzle, After.js и т. д. Поэтому если вы хорошо разберётесь в React.js, то пользоваться всеми этими фреймворками станет легче.
Смотрите также: React.js для продолжающих
Используйте фрагменты вместо div
Зачастую у нас на руках множество компонентов, которые приходится оборачивать в div
, т.к. render()
позволяет вернуть только один компонент. Таким образом мы добавляем в документ лишний HTML-элемент.
Согласно официальному руководству:
Порой мы нарушаем семантику HTML, когда добавляем элементы
<div>
в JSX, чтобы заставить код React работать, особенно при работе со списками (<ol>
,<ul>
и<dl>
) и таблицами<table>
. В таких случаях лучше использовать фрагменты React для группировки нескольких элементов.
import React, { Fragment } from 'react';
function ListItem({ item }) {
return (
<Fragment>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment>
);
}
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
<ListItem item={item} key={item.id} />
))}
</dl>
);
}
Больше информации можно найти в документации по фрагментам.
Пользуйтесь контекстом чаще
Благодаря контексту можно передавать данные через дерево компонентов, вместо того чтобы вручную передавать свойства на каждом уровне. Поэтому если у вас есть несколько компонентов, которым нужны данные, используйте контекст. Если у вас есть только один дочерний компонент, используйте композицию.
Пример установки темы из документации:
theme-context.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext(
themes.dark // значение по умолчанию
);
themed-button.js
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context;
return (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
// Промежуточный компонент, который использует ThemedButton
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}
render() {
// Кнопка ThemedButton внутри ThemeProvider
// использует тему из state, в то время как внешняя
// использует тёмную тему по умолчанию
return (
<Page>
<ThemeContext.Provider value={this.state.theme}>
<Toolbar changeTheme={this.toggleTheme} />
</ThemeContext.Provider>
<Section>
<ThemedButton />
</Section>
</Page>
);
}
}
ReactDOM.render(<App />, document.root);
Используйте хотя бы одни границы ошибок
В React 16 появилась такая замечательная вещь, как границы ошибок. По названию понятно, что это компоненты, которые отлавливают ошибки во всех дочерних компонентах. Идея очень проста: создайте компонент и используйте его в качестве родителя каждый раз, когда вам понадобится обрабатывать ошибки. Если в каком-то из дочерних компонентов возникнет ошибка, границы ошибок будут вызваны для обработки. Имейте в виду, что границы ошибок отлавливают ошибки отображения. Императивные ошибки вроде тех, что возникают в обработчиках событий, должны отлавливаться try
/catch
-блоком JavaScript.
Для логирования информации об ошибке нужно использовать componentDidCatch()
:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Обновляем состояние, чтобы следующее отображение
// показало интерфейс на случай ошибок
return { hasError: true };
}
componentDidCatch(error, info) {
// Также можно залогировать ошибку
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// Можно отобразить любой интерфейс на случай ошибок
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
Теперь его можно использовать как обычный компонент:
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
Если в самом компоненте ErrorBoundary
возникнет ошибка, он её не сможет обработать.
Такая функция была доступна в React 15 под названием unstable_handleError()
. Этот метод больше не работает, и с бета-релиза 16 версии вам нужно использовать componentDidCatch()
вместо него.
Разработчики React предоставили инструмент для автоматического изменения кода.
Используйте продакшн-сборку в реальной среде
На официальном сайте перечислены конфигурации, которые могут улучшить производительность. Не забудьте ознакомиться с ними перед развёртыванием в проде.
Здесь можно почитать руководство.
На конфигурацию уйдёт всего 10 минут, а взамен ваше приложение получит большой прирост к производительности.
Используйте ссылки ref для взаимодействия с дочерним элементом
Мы можем использовать ref’ы для активации анимации, выбора текста или управления фокусом. Например, чтобы установить фокус в React, мы можем ссылаться на элементы DOM. С помощью ref’ов мы сначала создаём ссылку на элемент в JSX класса компонента:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// Создаём ссылку для хранения элемента DOM textInput DOM
this.textInput = React.createRef();
}
render() {
// Используем callback ref, чтобы сохранить ссылку на элемент
// в поле экземпляра (например, this.textInput).
return (
<input
type="text"
ref={this.textInput}
/>
);
}
}
При необходимости мы можем установить фокус где угодно в компоненте:
focus() {
// Явно устанавливаем фокус с помощью DOM API
// Примечание: "current" нужен для получения доступа к узлу DOM
this.textInput.current.focus();
}
Подробнее в документации React.
Используйте разделение кода
Если вы используете CRA (create react app) или Next.js, то у вас уже должен быть готовый конфигурационный файл webpack. Он создаст один файл (бандл), который будет содержать всё ваше приложение. Если вы используете сторонние библиотеки и/или приложение увеличивается в размерах, то и бандл будет становиться больше. Когда пользователь зайдёт на сайт, браузер скачает весь бандл и затем всё отобразит. Это может сильно замедлить сайт, поэтому гораздо лучше разделить код и таким образом разбить бандл на части. В результате браузер будет закачивать нужные части по мере необходимости, что приведёт к улучшению времени загрузки сайта.
Для достижения нашей цели можно использовать React.lazy
.
Примечание React.lazy
и Suspense
пока нельзя использовать для отображения на стороне сервера. Для решения этой проблемы вы можете воспользоваться React Loadable. В документации можно найти хорошее руководство по разделению бандлов с серверным отображением.
Разделять код можно разными способами, но хорошей отправной точкой будет разделение на основе путей.
Как правило, переходы на новую страницу требуют времени на загрузку. А если вы заново отображаете всю страницу за раз, то пользователи, не могут взаимодействовать с другими элементами на странице в то же время.
Вот пример настройки разделения на основе путей с помощью библиотек вроде React Router и React.lazy
:
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Suspense>
</Router>
);
Suspense
нужен здесь на всякий случай: он будет показан, если нужный бандл ещё не загрузился. Здесь вы можете использовать индикатор загрузки, чтобы показать пользователям, что процесс не стоит на месте. Вы можете использовать границы ошибок даже в качестве родителя Suspense
для обработки других ошибок вроде сетевых.
React.lazy
пока что поддерживает только экспорт по умолчанию. Если вам нужно использовать именованные экспорты, загляните в документацию React.
Пользуйтесь статической проверкой типов
JavaScript является динамически и слабо типизированным языком, поэтому многие проблемы возникают из-за неправильных типов. Для решения этой проблемы можно использовать различные инструменты для проверки типов. Flow — известный и дружелюбный к новичкам вариант. Он был разработан в Facebook и часто используется с React. Он позволяет аннотировать переменные, функции и компоненты React с помощью специального синтаксиса и даёт возможность быстро отлавливать ошибки. Здесь можно изучить основы Flow, а в этом официальном руководстве найти пошаговые инструкции по использованию.
Итак, что же нужно делать, чтобы стать продвинутым разработчиком React
- Используйте фрагменты вместо div.
- Чаще пользуйтесь контекстом.
- Используйте границы ошибок.
- Используйте продакшн-сборку в реальной среде.
- Используйте ссылки ref для взаимодействия с дочерним элементом.
- Используйте разделение кода.
- Пользуйтесь статической проверкой типов.
Перевод статьи «Concepts to become an advanced React developer»