Доступность контента
Доступность контента — это специальные технические и архитектурные
решения, которые помогают людям с ограниченными возможностями
использовать сайты.
Семантическая вёрстка — это основа доступности контента в веб-
приложениях. Используя различные HTML-элементы можно улучшить
восприимчивость и понятность ваших сайтов. Это позволяет сделать контент
доступным без особых усилий.
2. Разделение кода
Большинство React-приложений «собирают» свои файлы такими
инструментами, как Webpack, Rollup или Browserify. Сборка (или
«бандлинг») — это процесс выявления импортированных файлов и
объединения их в один «собранный» файл (часто называемый «bundle» или
«бандл»). Этот бандл после подключения на веб-страницу загружает всё
приложение за один раз.
Пример:
Приложение:
// app.js
import { add } from './math.js';
console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
return a + b;
}
Бандл:
function add(a, b) {
return a + b;
}
console.log(add(16, 26)); // 42
Разделение кода
Бандлинг это хорошо, но по мере роста вашего приложения, ваш бандл тоже
будет расти. Особенно если вы подключаете крупные сторонние библиотеки.
Вам нужно следить за кодом, который вы подключаете, чтобы случайно не
сделать приложение настолько большим, что его загрузка займёт слишком
много времени.
console.log(add(16, 26));
После:
import("./math").then(math => {
console.log(math.add(16, 26));
});
3. Предохранители
Предохранители — это компоненты React, которые отлавливают ошибки
JavaScript в любом месте деревьев их дочерних компонентов, сохраняют их в
журнале ошибок и выводят запасной UI вместо рухнувшего дерева
компонентов.
Предохранители отлавливают ошибки при рендеринге, в методах жизненного
цикла и конструкторах деревьев компонентов, расположенных под ними.
Предохранители не поймают ошибки в:
обработчиках событий (подробнее);
асинхронном коде (например колбэках из setTimeout или
requestAnimationFrame);
серверном рендеринге (Server-side rendering);
самом предохранителе (а не в его дочерних компонентах).
Классовый компонент является предохранителем, если он включает хотя бы
один из следующих методов жизненного цикла: static
getDerivedStateFromError() или componentDidCatch(). Используйте static
getDerivedStateFromError() при рендеринге запасного UI в случае отлова
ошибки. Используйте componentDidCatch() при написании кода для
журналирования информации об отловленной ошибке.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
4. Перенаправление рефов
Перенаправление рефов позволяет автоматически передавать реф
компонента одному из его дочерних элементов. Большинству компонентов
перенаправление рефов не нужно, но оно может быть полезно, например,
если вы пишете библиотеку.
Перенаправление рефов позволяет взять ref из атрибутов компонента, и
передать («перенаправить») его одному из дочерних компонентов.
В данном примере
мы используем React.forwardRef в компоненте FancyButton, чтобы получить
реф и передать его в дочерний DOM-элемент button.
5. Фрагменты
Фрагменты позволяют формировать список дочерних элементов, не создавая
лишних узлов в DOM.
Мотивация
7. JSX в деталях
JSX — синтаксический сахар для функции React.createElement(component,
props, ...children). Этот JSX-код:
<MyButton color="blue" shadowSize={2}>
Нажми меня
</MyButton>
Скомпилируется в:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Нажми меня'
)
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Представьте, что здесь цвет {props.color} виджета выбора
даты.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;}
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Неправильно! JSX-тип не может являться выражением return
<components[props.storyType] story={props.story} />;}
Чтобы исправить это, мы присвоим тип в переменную, начинающуюся
с заглавной буквы:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Правильно! JSX-тип может являться переменной, названной с заглавной буквы
const SpecificStory = components[props.storyType]; return <SpecificStory
story={props.story} />;}
Пропсы в JSX
JavaScript-выражения как пропсы
Вы можете передавать любые JavaScript-выражения как пропсы, обернув их в
{}.
Оператор if и цикл for не являются выражениями в JavaScript, поэтому
их нельзя непосредственно использовать в JSX. Вместо этого, вы можете
окружить ими JSX-код. К примеру:
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) { description = <strong>чётным</strong>; } else
{ description = <i>нечётным</i>; } return <div>{props.number} является
{description} числом</div>;
}
function App2() {
const props = {firstName: 'Иван', lastName: 'Иванов'};
return <Greeting {...props} />;}
8. Порталы
Порталы позволяют рендерить дочерние элементы в DOM-узел, который
находится вне DOM-иерархии родительского компонента.
ReactDOM.createPortal(child, container)
Первый аргумент (child) — это любой React-компонент, который может быть
отрендерен, такой как элемент, строка или фрагмент. Следующий аргумент
(container) — это DOM-элемент.
9. Profiler
Profiler измеряет то, как часто рендерится React-приложение и какова
«стоимость» этого. Его задача — помочь найти медленные части
приложения, которые можно оптимизировать.
Profiler может быть добавлен в любую часть React-дерева для измерения
стоимости рендеринга этой части. Он принимает два пропа: id (string) и
колбэк onRender (function), который React вызывает каждый раз, когда
компонент внутри дерева «фиксирует» обновление.
render(
<App>
<Profiler id="Navigation" onRender={callback}>
<Navigation {...props} />
</Profiler>
<Main {...props} />
</App>
);
Для замера разных частей приложения могут быть использованы несколько
компонентов Profiler.
10. Соглосование
Алгоритм сравнения
При сравнении двух деревьев первым делом React сравнивает два корневых
элемента. Поведение различается в зависимости от типов корневых
элементов.
Элементы различных типов
Всякий раз, когда корневые элементы имеют различные типы, React
уничтожает старое дерево и строит новое с нуля. Переходы от <a> к <img>,
или от <Article> к <Comment>, или от <Button> к <div> приведут к полному
перестроению.
При уничтожении дерева старые DOM-узлы удаляются. Экземпляры
компонента получают componentWillUnmount(). При построении нового
дерева, новые DOM-узлы вставляются в DOM. Экземпляры компонента
получают componentWillMount(), а затем componentDidMount(). Любое
состояние, связанное со старым деревом, теряется.
DOM-элементы одного типа
12. Рендер-пропсы
Термин «рендер-проп» относится к возможности компонентов React
разделять код между собой с помощью пропа, значение которого является
функцией.
function ExampleApplication() {
return (
<div>
<Header />
<React.StrictMode> <div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode> <Footer />
</div>
);
}
Greeting.propTypes = {
name: PropTypes.string
};
PropTypes предоставляет ряд валидаторов, которые могут использоваться для
проверки, что получаемые данные корректны. В примере
мы использовали PropTypes.string. Когда какой-то проп имеет некорректное
значение, в консоли будет выведено предупреждение. По соображениям
производительности propTypes проверяются только в режиме разработки.
handleSubmit(event) {
alert('Отправленное имя: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Имя:
<input type="text" ref={this.input} /> </label>
<input type="submit" value="Отправить" />
</form>
);
}
}
React.Component
React.PureComponent
createElement();
createFactory();
React.Component
React.Component — это базовый класс для компонентов React, объявленных
как ES6-классы:
class Greeting extends React.Component {
render() {
return <h1>Привет, {this.props.name}</h1>;
}
}
React.memo
const MyComponent = React.memo(function MyComponent(props) {
/* рендер с использованием пропсов */
});
React.memo — это компонент высшего порядка. Он похож
на React.PureComponent, но предназначен для функциональных компонентов.
Если ваш функциональный компонент всегда рендерит одинаковый
результат для одних и тех же пропсов, вы можете обернуть его
в вызов React.memo для повышения производительности в некоторых
случаях, мемоизируя результат. Это значит, что React будет использовать
результат последнего рендера, избегая повторного рендеринга.
createElement()
React.createElement(
type,
[props],
[...children]
)
Создаёт и возвращает новый React-элемент определённого типа.
Аргументом type может быть строка, содержащая имя тега
(например, 'div' или 'span'), React-компонент (класс или функция) или React-
фрагмент.
cloneElement()
React.cloneElement(
element,
[props],
[...children]
)
Клонирует и возвращает новый React элемент, используя элемент в качестве
отправной точки. Полученный элемент будет иметь пропсы исходного
элемента, а новые пропсы будут поверхностно слиты воедино. Новые
дочерние элементы заменят существующие. key и ref из исходного элемента
будут сохранены.
isValidElement()
React.isValidElement(object)
Проверяет, что объект является элементом React. Возвращает true или false.
React.Children
React.Fragment
Компонент React.Fragment позволяет возвращать несколько элементов
в методе render() без создания дополнительного элемента DOM:
render() {
return (
<React.Fragment>
Какой-то текст.
<h2>Заголовок</h2>
</React.Fragment>
);
}
React.lazy
React.lazy() позволяет
вам определять компонент, который загружается
динамически. Это помогает уменьшить размер сборки, откладывая загрузку
компонентов, которые не используются во время первоначального рендера.
React.Suspense
React.Suspense позволяет
показать индикатор загрузки в случае, если
некоторые компоненты в дереве под ним ещё не готовы к рендеру. Сегодня
ленивая загрузка компонентов — это единственный вариант
использования, поддерживаемый <React.Suspense>:
2. React.Component
React позволяет определять компоненты как классы или функции.
В настоящее время классовые компоненты имеют больше возможностей.
Они разобраны на этой странице. Чтобы определить такой компонент,
необходимо отнаследоваться от React.Component:
class Welcome extends React.Component {
render() {
return <h1>Привет, {this.props.name}</h1>;
}
}
Единственный обязательный метод в подклассе React.Component — render().
Все остальные методы, описанные ниже, являются необязательными.
Монтирование
Обновление
Размонтирование
constructor()
constructor(props)
Вы можете не использовать конструктор в React-компоненте, если
вы не определяете состояние или не привязываете методы.
Конструктор компонента React вызывается до того, как компонент будет
примонтирован. В начале конструктора необходимо вызывать super(props).
Если это не сделать, this.props не будет определён. Это может привести
к багам.
getDerivedStateFromProps(props, state);
вызывается непосредственно перед вызовом метода render, как при
начальном монтировании, так и при последующих обновлениях. Он должен
вернуть объект для обновления состояния или null, чтобы ничего
не обновлять.
Этот метод существует для редких случаев, когда состояние зависит
от изменений в пропсах.
componentDidMount()
вызывается сразу после монтирования (то есть, вставки компонента в DOM).
В этом методе должны происходить действия, которые требуют наличия
DOM-узлов. Это хорошее место для создания сетевых запросов.
Используйте shouldComponentUpdate(nextProps, NextState),
чтобы указать необходимость следующего рендера на основе изменений
состояния и пропсов. По умолчанию происходит повторный рендер при
любом изменении состояния. В большинстве случаев вы должны полагаться
на это поведение.
shouldComponentUpdate() вызывается перед рендером, когда получает новые
пропсы или состояние. Значение по умолчанию равно true. Этот метод
не вызывается при первом рендере или когда используется forceUpdate().
Этот метод нужен только для повышения производительности
getSnapshotBeforeUpdate(prevProps, prevState) вызывается
прямо перед этапом «фиксирования» (например, перед добавлением
в DOM). Он позволяет вашему компоненту брать некоторую информацию
из DOM (например, положение прокрутки) перед её возможным
изменением. Любое значение, возвращаемое этим методом жизненного
цикла, будет передано как параметр componentDidUpdate()
static getDerivedStateFromError()
static getDerivedStateFromError(error)
componentDidCatch()
componentDidCatch(error, info)
ReactDOM
render()
ReactDOM.render(element, container[, callback])
Рендерит React-элемент в DOM-элемент, переданный
в аргумент container и возвращает ссылку на компонент (или
возвращает null для компонентов без состояния).
Если React-элемент уже был ранее отрендерен в container, то повторный
вызов произведёт его обновление и изменит соответствующую часть DOM,
чтобы она содержала последние изменения.
hydrate()
ReactDOM.hydrate(element, container[, callback])
То же, что и render(), но используется для гидратации контейнера, HTML-
содержимое которого было отрендерено с помощью ReactDOMServer. React
попытается присоединить обработчики событий к уже существующей
разметке.
unmountComponentAtNode()
ReactDOM.unmountComponentAtNode(container)
Удаляет смонтированный компонент React из DOM и очищает его
обработчики событий и состояние. Если в контейнер не было смонтировано
ни одного компонента, вызов этой функции ничего не делает.
Возвращает true, если компонент был размонтирован, и false если нет
компонента для размонтирования.
ReactDOM.findDOMNode(component)
Если этот компонент был смонтирован в DOM, он возвращает
соответствующий DOM элемент браузера. Этот метод полезен для чтения
напрямую из DOM (например, чтение значений полей формы) или
произведения измерений DOM. В большинстве случаев, вы можете
присоединить реф к узлу DOM и полностью избежать
использования findDOMNode.
createPortal()
ReactDOM.createPortal(child, container)
Создаёт портал. Порталы предоставляют способ отрендерить дочерние
элементы в узле DOM, который существует вне иерархии DOM-компонента.
ReactDOMServer
Объект ReactDOMServer позволяет отрендерить
компоненты в статическую разметку.
renderToString()
ReactDOMServer.renderToString(element)
renderToStaticNodeStream()
ReactDOMServer.renderToStaticNodeStream(element)
Похож на метод renderToNodeStream, но не создаёт дополнительных DOM-
атрибутов, таких как data-reactroot, используемых внутри React. Метод
полезен, когда вы хотите использовать React для генерации простой
статической страницы, где отсутствие дополнительных атрибутов может
сохранить несколько байтов.
Элементы DOM
В React все свойства и атрибуты DOM (включая обработчики событий)
должны быть в стиле camelCase. Например, HTML-
атрибут tabindex соответствует атрибуту tabIndex в React. Исключение
составляют атрибуты aria-* и data-*, которые следует писать в нижнем
регистре. В частности, вы можете оставить aria-label как aria-label.
checked
Атрибут checked поддерживается компонентами <input> типа checkbox или radio.
Он нужен для того, чтобы узнать выбран ли компонент. Это полезно для
создания управляемых компонентов. defaultChecked — это неуправляемый
эквивалент, который определяет, выбран ли компонент на момент первого
монтирования.
className
Чтобы указать класс CSS, используйте атрибут className. Это относится
ко всем обычным элементам DOM и SVG, таким как <div>, <a> и т. д.
Если вы используете React с веб-компонентами (что встречается редко),
используйте вместо этого атрибут class.
dangerouslySetInnerHTML
Свойству innerHTML в DOM браузера
соответствует dangerouslySetInnerHTML в React.
htmlFor
Поскольку for является зарезервированным словом JavaScript, для
определения HTML-атрибута for в элементах React вместо него
используйте htmlFor.
SyntheticEvent