Сложные вопросы на собеседовании по React

месяц назад·3 мин. на чтение

В данной статье рассматриваются сложные вопросы, которые могут быть заданы на собеседовании по React. Вопросы охватывают широкий спектр тем.

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

1. Что такое React и какие принципы лежат в его основе?

React – это JavaScript-библиотека, разработанная Facebook, которая используется для создания пользовательских интерфейсов. Одной из главных особенностей React является использование виртуального DOM (Virtual DOM), который при значительном изменении состояния компонента или данных эффективно обновляет только необходимые элементы интерфейса. React также основан на принципе однонаправленного потока данных, где данные передаются от верхнего родительского компонента к дочерним.

2. В чем разница между компонентами классов и функциональными компонентами?

Классовые компоненты являются старым подходом к созданию компонентов в React и используются для создания сложных компонентов, которые имеют внутреннее состояние и методы жизненного цикла. Функциональные компоненты – это новый подход, появившийся с появлением React Hooks, который позволяет создавать компоненты в виде функций. Такие компоненты проще и более читабельны, но не имеют встроенной поддержки состояния и методов жизненного цикла. Однако с помощью хуков можно добавить их в функциональные компоненты.

3. Что такое контекст (context) в React и для чего он используется?

Контекст – это механизм, предоставляемый React, который позволяет передавать данные через иерархию компонентов без явной передачи пропсов по каждому уровню. Контекст особенно полезен, когда некоторые данные должны быть доступны во многих компонентах на разных уровнях иерархии. Он также позволяет избежать "прокидывания" пропсов через несколько слоев компонентов.

4. Что такое React Hooks и для чего они используются?

React Hooks представляют собой новое API, добавленное в React версии 16.8, которое позволяет использовать состояние и другие функциональности React в функциональных компонентах. Они позволяют избежать использования классовых компонентов и добавляют возможности, такие как использование состояния (useState), эффектов (useEffect) и контекста (useContext). Они упрощают разработку и делают код компонентов более чистым и читабельным.

5. Что такое виртуальный DOM (Virtual DOM) в React и как он работает?

Виртуальный DOM – это внутренняя структура данных, используемая React, которая представляет набор элементов интерфейса в виде JS-объектов. Когда состояние компонента или данные изменяются, React создает новую виртуальную DOM-структуру и сравнивает ее с предыдущей. Затем React определяет разницу между новым и старым состоянием и эффективно обновляет только изменившиеся элементы на странице реального DOM. Это позволяет значительно увеличить производительность при рендеринге больших и сложных интерфейсов.

6. Как происходит передача данных между компонентами в React?

В React данные между компонентами передаются через пропсы (props). Пропсы – это параметры, передаваемые в компонент при его использовании. Они позволяют передавать данные от родительского компонента к дочернему, а также вызывать функции из родительского компонента в дочернем. Для передачи данных вниз по иерархии компонентов используется подход "однонаправленного потока данных".

7. Каким образом можно оптимизировать производительность компонентов в React?

Оптимизация производительности компонентов в React может выполняться с помощью следующих методов:
  • Мемоизация компонентов с помощью
  • PureComponent или React.memo
  • Использование ключей (keys) в списках элементов
  • Ленивая загрузка компонентов (React.lazy)
  • Пакетная обработка (батчинг)
  • Оптимизация работы с внешними источниками данных (например, работа с API)
  • Использование shouldComponentUpdate или PureComponent для предотвращения ненужных ререндеров
  • Оптимизация избыточного рендеринга (например, с помощью useEffect)
В этой статье мы рассмотрели несколько сложных вопросов и ответов на собеседовании по React. Это не исчерпывающий список, и ваше опыт и знания могут варьироваться. Однако эти вопросы и ответы помогут вам подготовиться к собеседованию и продемонстрировать свои знания React.

Как передать пропсы React компоненту

2 года назад·5 мин. на чтение

Компоненты React используют пропсы (props) для связи друг с другом. Каждый родительский компонент может передавать некоторую информацию своим дочерним компонентам, предоставляя им пропсы. Пропсы могут напоминать атрибуты HTML, но вы можете передавать через них любое значение JavaScript, включая объекты, массивы и функции.

Содержание туториала по React Компоненты React используют пропсы (props) для связи друг с другом. Каждый родительский компонент может передавать некоторую информацию своим дочерним компонентам, предоставляя им пропсы. Пропсы могут напоминать атрибуты HTML, но вы можете передавать через них любое значение JavaScript, включая объекты, массивы и функции.

Известные пропсы

Пропсы — это информация, которую вы передаете тегу JSX. Например, className, src, alt, width и height — вот некоторые пропсы, которые вы можете передать <img>:
function Avatar() {
  return (
    <img
      className="avatar"
      src="https://example.com/userpic.jpg"
      alt="Userpic"
      width={100}
      height={100}
    />
  );
}

export default function Profile() {
  return <Avatar />;
}
Пропсы, которые вы можете передать тегу <img>, предопределены (ReactDOM соответствует стандартам HTML). Но вы можете передать любые пропсы своим собственным компонентам, таким как <Avatar>, чтобы настроить их.

Передача пропсов в компонент

В этом коде компонент Profile не передает никаких пропсов своему дочернему компоненту Avatar:
export default function Profile() {
  return <Avatar />;
}
Вы можете передать в Avatar некоторые пропсы в два этапа.

Шаг 1: Передайте пропсы дочернему компоненту

Во-первых, передайте некоторые пропсы в Avatar. Например, давайте передадим два пропса: person (объект) и size (число):
export default function Profile() {
  return (
    <Avatar person={{ name: 'User Name 1', imageId: '12345' }} size={100} />
  );
}
Если двойные фигурные скобки после person= вас смущают, помните, что они являются просто объектом внутри фигурных скобок JSX. Теперь вы можете прочитать эти пропсы внутри компонента Avatar.

Шаг 2: Прочтите пропсы внутри дочернего компонента

Вы можете прочитать эти пропсы, указав их имена - person, size - разделенные запятыми внутри ({ и }) непосредственно после function Avatar. Это позволяет использовать их внутри кода Avatar, как если бы вы использовали переменную.
function Avatar({ person, size }) {
  // person и size можно здесь использовть
}
Добавьте немного логики в Avatar, которая использует пропсы person, size в отображении, и все готово. Теперь вы можете настроить Avatar для отображения разными способами с разными пропсы.
// utils.js

export function getImageUrl(person, size = 's') {
  return 'https://example.com/' + person.imageId + size + '.jpg';
}
// App.js

import { getImageUrl } from './utils.js';

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{
          name: 'User Name 1',
          imageId: '12345',
        }}
      />
      <Avatar
        size={80}
        person={{
          name: 'User Name 2',
          imageId: '12346',
        }}
      />
      <Avatar
        size={50}
        person={{
          name: 'User Name 3',
          imageId: '12347',
        }}
      />
    </div>
  );
}
Пропсы позволяют вам думать о родительских и дочерних компонентах независимо друг от друга. Например, вы можете изменить пропсы person или size внутри Profile, не задумываясь о том, как Avatar их использует. Точно так же вы можете изменить то, как Avatar использует эти пропсы, не заглядывая в Profile. Вы можете думать о пропсах как о «ручках», которые вы можете регулировать. Они выполняют ту же роль, что и аргументы для функций — на самом деле пропсы являются единственным аргументом для вашего компонента. Функции компонента React принимают один аргумент, объект props:
function Avatar(props) {
  let person = props.person;
  let size = props.size;
  // ...
}
Обычно вам не нужен весь объект пропса, поэтому можно разбить его на отдельные пропсы. Не пропустите пару фигурных скобок { и } внутри ( и ) при объявлении пропсов:
function Avatar({ person, size }) {
  // ...
}
Этот синтаксис называется «деструктурированием» и эквивалентен чтению свойств из параметра функции:
function Avatar(props) {
  let person = props.person;
  let size = props.size;
  // ...
}

Как указать значения по умолчанию для пропса

Если вы хотите присвоить пропсу значение по умолчанию, чтобы использовать его, когда значение не указано, вы можете сделать это с помощью деструктуризации, поставив = и значение по умолчанию сразу после параметра:
function Avatar({ person, size = 100 }) {
  // ...
}
Теперь, если в <Avatar person={...} /> передан пропс size, размер будет установлен на 100. Значение по умолчанию используется только в том случае, если параметр size отсутствует или если вы передаете size={undefined}. Но если вы передадите size={null} или size={0}, значение по умолчанию не будет использоваться.

Перенаправление пропсов с синтаксисом распыления JSX

Иногда отправка пропсов повторяется:
function Profile({ person, size, isSepia, thickBorder }) {
  return (
    <div className="card">
      <Avatar
        person={person}
        size={size}
        isSepia={isSepia}
        thickBorder={thickBorder}
      />
    </div>
  );
}
В повторяющемся коде нет ничего плохого. Но иногда хочется сделать код короче. Некоторые компоненты передают все свои пропсы своим дочерним компонентам, например, как Profile делает с Avatar. Поскольку они не используют никакие свои пропсы напрямую, может иметь смысл использовать более краткий синтаксис распыления (spread):
function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}
Это пример перенаправления всех пропсов Profile в Avatar без перечисления каждого из их имен. Используйте расширенный синтаксис с ограничениями. Если вы используете его в каждом компоненте - значит что-то не так. Часто это указывает на то, что следует разделить компоненты и передать дочерние компоненты как JSX. Подробнее об этом далее.

Передача JSX в качестве дочернего компонента

Обычно встроенные теги браузера вкладывают друг в друга:
<div>
  <img />
</div>
Иногда вы захотите вложить свои собственные компоненты таким же образом:
<Card>
  <Avatar />
</Card>
Когда вы вкладываете контент в тег JSX, родительский компонент получит этот контент в просе, называемом children. Например, компонент Card ниже получит проп children, который является <Avatar />, и отобразит его в обертке div:
// App.js

import Avatar from './Avatar.js';

function Card({ children }) {
  return <div className="card">{children}</div>;
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'User Name',
          imageId: '12345',
        }}
      />
    </Card>
  );
}
// Avatar.jsx

import { getImageUrl } from './utils.js';

export default function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}
// utils.js

export function getImageUrl(person, size = 's') {
  return 'https://example.com/' + person.imageId + size + '.jpg';
}
Вы можете думать о компоненте с пропсом children как о специальной лозейке, которую можно «заполнить» родительскими компонентами с произвольным JSX. Вы часто будете использовать проп children для визуальных оболочек: панелей, сеток и т.д.

Как пропсы меняются со временем

Компонент Clock ниже получает два пропса от своего родительского компонента: color и time. (Код родительского компонента опущен, поскольку он использует состояние, в которое мы пока не будем углубляться.)
export default function Clock({ color, time }) {
  return <h1 style={{ color: color }}>{time}</h1>;
}
Этот пример иллюстрирует, что компонент может получать пропсы с течением времени. Проп не всегда статичен. Здесь проп time меняется каждую секунду, а проп color меняется, когда вы выбираете другой цвет. Пропсы отражают данные компонента в любой момент времени, а не только в начале. Пропсы иммутабельны — термин из информатики, означающий «неизменяемый». Когда компоненту необходимо изменить свои пропсы (например, в ответ на взаимодействие с пользователем или новые данные), ему придется «попросить» родительский компонент передать ему другие пропсы — новый объект. Затем его старые пропсы будут отброшены, и в конечном итоге движок JavaScript очистит занятую ими память. Не пытайтесь "изменить пропсы" напрямую. Когда вам нужно отреагировать на пользовательский ввод (например, изменить выбранный цвет), вам нужно будет "установить состояние", о котором вы можете узнать в разделе "Состояние - память компонента".

Резюме

  • Чтобы передать пропсы, добавьте их в JSX, как и в случае с атрибутами HTML.
  • Чтобы прочитать пропсы, используйте синтаксис деструктурирования function Avatar({ person, size }).
  • Вы можете указать значение по умолчанию, например size = 100, которое используется для отсутствующих и неопределенных пропсов.
  • Вы можете перенаправить все пропсы с помощью синтаксиса распыления JSX <Avatar {...props} />, но не злоупотребляйте им.
  • Вложенный JSX, такой как <Card><Avatar /></Card>, будет отображаться как проп children компонента Card.
  • Пропсы - доступны только для чтения. Это такой снимок компонента во времени: каждый рендер получает новую версию пропса.
  • Нельзя менять пропсы внутри компонента. Когда вам нужна интерактивность, вам нужно установить состояние.