Быстрый старт с React
2 года назад·7 мин. на чтение
React приложения состоят из компонентов. Компонент — это часть UI (пользовательского интерфейса), которая имеет собственную логику и внешний вид. Компонент может быть маленьким, как кнопка, или большим, как целая страница.
Содержание туториала по React
Эта страница познакомит вас с 80% концепций React, которые вы будете использовать ежедневно.
Во-первых, переместите состояние из
Когда вы нажимаете кнопку, срабатывает обработчик
Создание компонентов
React приложения состоят из компонентов. Компонент — это часть UI (пользовательского интерфейса), которая имеет собственную логику и внешний вид. Компонент может быть маленьким, как кнопка, или большим, как целая страница. React компоненты — это функции JavaScript, которые возвращают разметку:Теперь, когда вы объявилиfunction MyButton() { return <button>I'm a button</button>; }
MyButton
, вы можете вложить его в другой компонент:
Обратите внимание, чтоexport default function MyApp() { return ( <div> <h1>Welcome to my app</h1> <MyButton /> </div> ); }
<MyButton />
начинается с заглавной буквы. Так мы узнаем, что это React компонент. Имена React компонентов всегда должны начинаться с заглавной буквы, а теги HTML должны быть строчными.
Ключевые слова export default
определяют главный компонент в файле.
Написание разметки с помощью JSX
Синтаксис разметки, который вы видели выше, называется JSX. Это необязательно, но большинство проектов React используют JSX для удобства. Все рекомендуемые для локальной разработки инструменты, поддерживают JSX «из коробки». JSX строже, чем HTML. Вы должны закрыть теги типа<br />
. Ваш компонент также не может возвращать несколько тегов JSX. Вы должны обернуть их в общий родитель, например <div>...</div>
или пустую оболочку <>...</>
:
Если у вас есть много HTML для переноса в JSX, вы можете использовать онлайн-конвертер.function AboutPage() { return ( <> <h1>About</h1> <p> Hello there. <br /> How do you do? </p> </> ); }
Добавление стилей
В React вы указываете CSS класс с помощьюclassName
. Он работает так же, как атрибут class
в HTML:
Затем вы пишете правила CSS для него в отдельном файле CSS:<img className="avatar" />
React не предписывает, как добавлять файлы CSS. В самом простом случае вы добавите тег/* In your CSS */ .avatar { border-radius: 50%; }
<link>
в свой HTML. Если вы используете инструмент сборки или фреймворк, обратитесь к его документации, чтобы узнать, как добавить файл CSS в свой проект.
Отображение данных
JSX позволяет размещать разметку в JavaScript. Фигурные скобки позволяют вам «уйти обратно» в JavaScript, чтобы вы могли внедрить некоторую переменную из своего кода и отобразить ее пользователю. Например, это отобразитuser.name
:
Вы также можете «убежать в JavaScript» из атрибутов JSX, но вам нужно использовать фигурные скобки вместо кавычек. Например,return <h1>{user.name}</h1>;
className="avatar"
передает строку "avatar"
как CSS класс, но src={user.imageUrl}
считывает значение JavaScript переменной user.imageUrl
, а затем передает это значение как атрибут src
:
Вы также можете поместить более сложные выражения в фигурные скобки JSX, например, конкатенацию строк:return <img className="avatar" src={user.imageUrl} />;
В приведенном выше примереconst user = { name: 'Hedy Lamarr', imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg', imageSize: 90, }; export default function Profile() { return ( <> <h1>{user.name}</h1> <img className="avatar" src={user.imageUrl} alt={'Photo of ' + user.name} style={{ width: user.imageSize, height: user.imageSize, }} /> </> ); }
style={{}}
не является специальным синтаксисом, а является обычным объектом {}
внутри фигурных скобок style={ }
JSX. Вы можете использовать атрибут style
, когда ваши стили зависят от переменных JavaScript.
Рендеринг по условию
В React нет специального синтаксиса для написания условий. Вместо этого можно использовать те же приемы, что и при написании обычного JavaScript кода. Например, вы можете использовать операторif
для условного включения JSX:
Если вы предпочитаете более компактный код, вы можете использовать условный ? оператор. В отличие отlet content; if (isLoggedIn) { content = <AdminPanel />; } else { content = <LoginForm />; } return <div>{content}</div>;
if
, он работает внутри JSX:
Если вам не нужна ветвь<div>{isLoggedIn ? <AdminPanel /> : <LoginForm />}</div>
else
, вы также можете использовать более короткий синтаксис логического &&:
Все эти подходы также работают для указанных по условию атрибутов. Если вы не знакомы с некоторыми элементами этого синтаксиса JavaScript, вы можете начать с постоянного использования<div>{isLoggedIn && <AdminPanel />}</div>
if...else
.
Рендеринг списков
Вы будете полагаться на возможности JavaScript, такие как цикл for и метод массива map() для отображения списков компонентов. Например, допустим, у вас есть набор продуктов:Внутри вашего компонента используйте методconst products = [ { title: 'Cabbage', id: 1 }, { title: 'Garlic', id: 2 }, { title: 'Apple', id: 3 }, ];
map()
для преобразования массива продуктов в массив элементов <li>
:
Обратите внимание, чтоconst listItems = products.map((product) => ( <li key={product.id}>{product.title}</li> )); return <ul>{listItems}</ul>;
<li>
имеет атрибут key
. Для каждого элемента в списке вы должны передать строку или число, которое однозначно идентифицирует этот элемент среди его соседних элементов. Обычно ключ должен исходить из ваших данных, таких как идентификатор базы данных. React будет полагаться на ваши ключи, чтобы понять, что произошло, если вы позже вставите, удалите или измените порядок элементов.
const products = [ { title: 'Cabbage', isFruit: false, id: 1 }, { title: 'Garlic', isFruit: false, id: 2 }, { title: 'Apple', isFruit: true, id: 3 }, ]; export default function ShoppingList() { const listItems = products.map((product) => ( <li key={product.id} style={{ color: product.isFruit ? 'magenta' : 'darkgreen', }} > {product.title} </li> )); return <ul>{listItems}</ul>; }
Реакция на события
Вы можете реагировать на события, объявляя функции обработчиков событий внутри ваших компонентов:Обратите внимание, чтоfunction MyButton() { function handleClick() { alert('You clicked me!'); } return <button onClick={handleClick}>Click me</button>; }
onClick={handleClick}
не имеет круглых скобок в конце. Не вызывайте функцию обработчика событий: вам нужно только передать ее вниз. React вызовет ваш обработчик событий, когда пользователь нажмет кнопку.
Обновление компонентов
Часто необходимо, чтобы компонент «запоминал» некоторую информацию и отображал ее. Например, может быть, вы хотите подсчитать, сколько раз была нажата кнопка. Для этого нужно добавить состояние к компоненту. Во-первых, импортируйтеuseState
из React:
Теперь вы можете объявить переменную состояния внутри вашего компонента:
Отfunction MyButton() { const [count, setCount] = useState(0);
useState
вы получите две вещи: текущее состояние (count
) и функцию, которая позволяет вам его обновить (setCount
). Вы можете давать им любые имена, но принято называть их как [something, setSomething]
.
При первом отображении кнопки count
будет равен 0
, потому что вы передали 0
в useState()
. Если вы хотите изменить состояние, вызовите setCount()
и передайте ему новое значение. Нажатие на эту кнопку увеличит счетчик:
React снова вызовет функцию вашего компонента. На этот раз счет будетfunction MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return <button onClick={handleClick}>Clicked {count} times</button>; }
1
. Затем будет 2
. И так далее.
Если вы визуализируете один и тот же компонент несколько раз, каждый из них получит свое собственное состояние.
Обратите внимание, как каждая кнопка «запоминает» свое собственное состояние счетчика и не влияет на другие кнопки.import { useState } from 'react'; export default function MyApp() { return ( <div> <h1>Counters that update separately</h1> <MyButton /> <MyButton /> </div> ); } function MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return <button onClick={handleClick}>Clicked {count} times</button>; }
Использование хуков
Функции, начинающиеся сuse
, называются хуками. useState
— это встроенный хук, предоставляемый React. Вы можете найти другие встроенные хуки в справочнике React API. Вы также можете написать свои собственные хуки, комбинируя существующие.
Хуки накладывают больше ограничений, чем обычные функции. Вы можете вызывать хуки только на верхнем уровне ваших компонентов (или других хуков). Если вы хотите использовать useState
в условии или цикле, создайте новый компонент и поместите его туда.
Обмен данными между компонентами
В предыдущем примере у каждойMyButton
был собственный независимый счетчик, и при нажатии каждой кнопки менялся только счетчик нажатой кнопки.
Однако часто вам потребуются компоненты для обмена данными и постоянного обновления вместе.
Чтобы оба компонента MyButton
отображали одно и то же число и обновлялись вместе, вам нужно переместить состояние от отдельных кнопок «вверх» к ближайшему родительскому компоненту, содержащему их все.
Теперь, когда вы нажмете любую кнопку, счетчик в MyApp
изменится, что изменит оба счетчика в MyButton
. Вот как это можно выразить в коде.
MyButton
в MyApp
:
Затем передайте состояние изexport default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update separately</h1> <MyButton /> <MyButton /> </div> ); } function MyButton() { // }
MyApp
в каждый MyButton
вместе с общим обработчиком кликов. Вы можете передавать информацию в MyButton
с помощью фигурных скобок JSX, точно так же, как вы делали это раньше со встроенными тегами, такими как <img>
:
Информация, которую вы передаете таким образом, называется пропсами. Теперь компонентexport default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Счетчики, изменяющиеся вместе</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); }
MyApp
содержит состояние счетчика и обработчик события handleClick
и передает их оба в качестве пропсов каждой из кнопок.
Наконец, измените MyButton
, чтобы он считывал пропсы, которые вы передали из его родительского компонента:
function MyButton({ count, onClick }) { return <button onClick={onClick}>Clicked {count} times</button>; }
onClick
. Проп onClick
каждой кнопки было установлено на функцию handleClick
внутри MyApp
, поэтому код внутри него выполняется. Этот код вызывает setCount(count + 1)
, увеличивая переменную состояния count
. Новое значение счетчика передается в качестве пропса каждой кнопке, поэтому все они показывают новое значение.
Это называется «подъем состояния вверх». Переместив состояние вверх, мы разделили его между компонентами.
Подробнее о всех случаях передачи данных между компонентами можно прочитать здесь.import { useState } from 'react'; export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Счетчики, изменяющиеся вместе</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); } function MyButton({ count, onClick }) { return <button onClick={onClick}>Clicked {count} times</button>; }
Вопросы и ответы React собеседования 2023 - Часть 1
2 года назад·6 мин. на чтение
Актуальный список вопросов и ответов по ReactJS на собеседовании 2023
- Вопросы и ответы ReactJS собеседования 2023 - Часть 1 (эта статья)
- Вопросы и ответы ReactJS собеседования 2023 - Часть 2
- Вопросы и ответы ReactJS собеседования 2023 - Часть 3
1. Как работает React?
React создает виртуальный DOM. Когда состояние компонента изменяется, он сначала запускает алгоритм сравнения, который идентифицирует, что изменилось в виртуальном DOM. Второй шаг — согласование (reconciliation), при котором DOM обновляется результатами из сравнения.2 Каковы достоинства использования React?
- Легко узнать, как визуализируется компонент, вам просто нужно взглянуть на функцию рендеринга.
- JSX упрощает чтение кода ваших компонентов. Также очень легко увидеть макет или то, как компоненты подключены/объединены.
- Вы можете рендерить React на стороне сервера. Это улучшает SEO и производительность.
- Легко тестировать.
3. В чем разница между презентационным компонентом и компонентом-контейнером?
Презентационные компоненты связаны с тем, как компоненты выглядят. Обычно они получают данные и колбэки через пропсы. Эти компоненты редко имеют собственное состояние, но когда они это делают, это обычно касается состояния пользовательского интерфейса, а не состояния данных. Когда ваш компонент просто получает пропсы и отображает их на странице, это компонент без состояния, для которого можно использовать чистую функцию. Их также называют тупыми компонентами (dumb components) или презентационными компонентами. Компоненты-контейнеры заботятся о том, как все работает. Эти компоненты предоставляют данные и поведение презентационным или другим компонентам-контейнерам. Они определяют действия и предоставляют их как функции обратных вызовов презентационным компонентам. Они также часто имеют состояние, поскольку служат источниками данных.4. Каковы различия между компонентом класса и функциональным компонентом?
Компонент класса использует синтаксис класса ES6 и расширяет компоненты React с помощью метода рендеринга, который возвращает элементы React. Функциональные компоненты с хуками — это обычные JavaScript функции, которые также возвращают элементы React. До появления хуков функциональные компоненты не могли иметь состояния.5. В чем разница между состоянием и пропсами?
Состояние — это структура данных, которая начинается со значения по умолчанию при монтировании компонента. Он может видоизменяться со временем, в основном в результате пользовательских событий. Пропсы (сокращение от properties, props) — это конфигурация компонента. Они получены сверху из компонента родителя и неизменяемы (иммутабельны). Компонент не может изменять свои пропсы. Функции обратного вызова также можно передавать в качестве пропсов.6. Какие существуют методы жизненного цикла?
componentWillMount
(устаревший) — чаще всего используется для настройки приложения в корневом компоненте.componentDidMount
— здесь вы можете сделать всю настройку, которую вы не смогли бы сделать без DOM, и начать получать все необходимые вам данные. Кроме того, если вы хотите настроить прослушиватели событий и т. д., этот хук жизненного цикла — хорошее место для этого.componentWillReceiveProps
(устаревший) — этот жизненный цикл действует на определенные изменения пропсов, чтобы вызвать переходы состояний.shouldComponentUpdate
— если вы беспокоитесь о потраченных впустую рендерах,shouldComponentUpdate
— отличное место для повышения производительности, поскольку оно позволяет предотвратить повторный рендеринг, если компонент получает новый проп.shouldComponentUpdate
всегда должен возвращать логическое значение, и на его основе будет определяться, будет ли компонент перерисован или нет.componentWillUpdate
(устаревший) — используется редко. Его можно использовать вместоcomponentWillReceiveProps
для компонента, у которого также естьshouldComponentUpdate
(но нет доступа к предыдущим значениям пропсов).componentDidUpdate
— также обычно используется для обновления DOM в ответ на изменение пропсов или состояния.componentWillUnmount
— позволяет отменить любые исходящие сетевые запросы или удалить все прослушиватели событий, связанные с компонентом. Вызывается перед размонтированием компонента.
7. Что такое хуки в React?
Хуки позволяют вам использовать больше функций React без использования классов. Первый хук, с которым вы, скорее всего, столкнетесь, этоuseState
. useState
— это хук, который позволяет добавлять состояние React к компонентам-функциям. Он возвращает массив с геттером и сеттером.
Синтаксис выглядит так:
Эквивалентом при использовании компонента класса будет.const [count, setCount] = React.useState(0); <button onClick={() => setCount(count + 1)}>Increase Count</button>;
Следующий хук, с которым вы, скорее всего, столкнетесь, этоthis.state = { count: 0, }; <button onClick={() => this.setState({ count: this.state.count + 1 })}> Increase Count </button>;
useEffect
. Хук эффектов позволяет выполнять побочные эффекты в функциональных компонентах. Передача пустого массива в качестве второго аргумента useEffect
эквивалентна использованию componentDidMount
. Если вы передадите значение в массив, функция useEffect
будет вызываться только при обновлении значения в массиве.
Подробнее о хуках:useEffect(() => { // делаем что-то, когда компонент монтируется }, []);
useId
useContext
useMemo
,useCallback
useMemo
,useCallback
(видео)useTransition
иuseDeferredValue
useImperativehandle
(видео)useLayoutEffect
(видео)useReducer
(видео)- Все хуки ReactJS до версии React 18 (видео)
8. Где стоит выполнять AJAX/API запрос в классовом React компоненте?
componentDidMount
— это место, где должен быть сделан запрос AJAX в компоненте React. Этот метод будет выполнен, когда компонент монтируется (добавляется в DOM) в первый раз. Этот метод выполняется только один раз в течение жизненного цикла компонента.
9. Что такое управляемые компоненты?
В HTML элементы формы, такие как<input>
, <textarea>
и <select>
, обычно поддерживают свое собственное состояние и обновляют его на основе ввода пользователя. Когда пользователь отправляет форму, значения из упомянутых элементов отправляются вместе с формой. С React это работает иначе. Компонент, содержащий форму, будет отслеживать значение ввода в своем состоянии и будет повторно отображать компонент каждый раз, когда запускается функция обратного вызова, например, onChange
, когда состояние будет обновлено. Элемент формы ввода, значение которого управляется React таким образом, называется управляемым компонентом.
Видео про управляемые компоненты.
10. Для чего в React используются рефы?
Рефы используются для получения ссылки на DOM узел или экземпляр компонента в React. Хорошими примерами использования ссылок являются управление фокусом/выбором текста, запуск императивной анимации или интеграция со сторонними DOM библиотеками.11. Что такое компоненты высшего порядка?
Компонент высшего порядка (Higher Order Component, HOC) — это компонент, который принимает компонент и возвращает новый компонент. HOC позволяют повторно использовать код и инициализировать компонент. Наиболее популярным HOC является функцияconnect
из Redux. Помимо простого совместного использования библиотек и простой композиции, HOC — лучший способ хранить общее поведение между React компонентами. Если вы обнаружите, что пишете много кода в разных местах, который делает одно и то же, вы можете реорганизовать этот код в многоразовый HOC.
Видео по теме:
12. Какие преимущества дает использование стрелочных функций?
- Безопасность области действия: до появления стрелочных функций каждая новая функция определяла собственное значение
this
(новый объект в случае конструктора,undefined
в вызовах функций в строгом режиме или базовый объект, если функция вызывается как «метод объекта» и т. д.). Стрелочная функция не создает собственногоthis
, используется значениеthis
окружающего контекста выполнения. - Компактность: стрелочные функции легче читать и писать.
- В классовых React компонентах стрелочные функции удобнее использовать для того чтобы избежать байндинга методов при передаче их в качестве функций обратного вызова.
13. Как бы вы предотвратили рендеринг классового компонента?
Возвратnull
из метода рендеринга компонента означает, что ничего не будет отображаться, но это не влияет на срабатывание методов жизненного цикла компонента.
Если количество повторных рендеров компонента является проблемой, доступны два варианта. Ручная реализация проверки в методе жизненного цикла shouldComponentUpdate
.
Или использоватьshouldComponentUpdate(nextProps, nextState){ const allowRender = true; // Делаем здесь некоторую проверку и назначаем решение в allowRender return allowRender }
React.PureComponent
вместо React.Component
. React.PureComponent
реализует shouldComponentUpdate()
с поверхностным сравнением пропсов и состояний. Это позволяет избежать повторного рендеринга компонента со значениями просов и состояний, которые не поменялись.
14. Что такое key при рендеринге списка и для чего он нужен?
Key помогают React определить, какие элементы были изменены, добавлены или удалены. Ключи должны быть даны элементам внутри массива, чтобы однозначно идентифицировать элементы. Лучший способ выбрать ключ — использовать строку, которая однозначно идентифицирует элемент списка среди его соседей, например,id
. Чаще всего вы будете использовать идентификаторы из ваших данных в качестве ключей. Если у вас нет стабильных идентификаторов для отображаемых элементов, вы в крайнем случае можете использовать индекс элемента в качестве ключа. Не рекомендуется использовать индексы для ключей, т.к. это может привести к неверному отображению элементов в случае их удаления или изменения порядка.
Также key можно использовать для пересоздания компонентов.
15. Для чего нужно вызывать super(props)
?
Конструктор дочернего класса не может использовать this
до тех пор, пока не будет вызвана функция super()
. Кроме того, конструкторы классов ES2015 должны вызывать super()
, если они являются подклассами. Причина передачи пропса в super()
заключается в том, чтобы вы могли получить доступ к this.props
в конструкторе.
Хочешь узнать больше? Еще вопросы с собеседований.