React Front-end Инженер

React Front-end Инженер

Роадмап навыков для прокачки

Почему до React 17 требовалось импортировать React

ReactСинтаксис JSXReact без JSX

Основная идея

До React 17 JSX-код трансформировался в вызовы React.createElement(), поэтому React должен был быть доступен в области видимости каждого файла, использующего JSX.

Ключевые аспекты

  • JSX — не валидный JavaScript — браузер не понимает синтаксис <Component />, его нужно преобразовать
  • Babel трансформация<div>Hello</div> превращался в React.createElement('div', null, 'Hello')
  • Область видимости — без import React вызов React.createElement приводил к ошибке React is not defined
  • React 17+ — новый JSX Transform автоматически импортирует нужные функции из react/jsx-runtime

Плюсы нового подхода (React 17+)

  • Меньше boilerplate-кода
  • Небольшое уменьшение размера бандла
  • Не нужно помнить об импорте React в каждом файле с JSX

Минусы старого подхода (до React 17)

  • Обязательный импорт даже если React явно не используется
  • Линтеры ругались на "неиспользуемый импорт"
  • Больше кода в каждом компоненте

Частые ошибки на собеседованиях

  • Путают JSX с HTML — JSX это синтаксический сахар над JavaScript
  • Не знают про новый JSX Transform в React 17
  • Думают, что React нужен для работы хуков — хуки работают благодаря внутреннему механизму React, а импорт был нужен именно для JSX

Введение и проблематика

При работе с React разработчики пишут код на JSX — специальном синтаксисе, который выглядит как HTML, но на самом деле является JavaScript. Браузер не понимает JSX напрямую, поэтому код должен быть преобразован в обычный JavaScript перед выполнением.

До React 17 каждый файл с JSX требовал явного импорта React, даже если вы не использовали его напрямую в коде.

Почему это было важно?

Без понимания этого механизма разработчик мог:

  • Получать непонятные ошибки React is not defined
  • Не понимать, зачем нужен "неиспользуемый" импорт
  • Конфликтовать с линтерами, которые предлагали удалить импорт

Базовая теория

Что такое JSX?

JSX (JavaScript XML) — это расширение синтаксиса JavaScript, позволяющее писать разметку внутри JS-файлов:

jsx
// Это JSX
const element = <h1 className="title">Привет, мир!</h1>;

Как работала трансформация до React 17

Babel (или другой транспилятор) преобразовывал JSX в вызовы React.createElement():

Code Example 1: Во что Babel преобразует JSX? Почему требовался импорт React?

jsx
// Исходный код с JSX
function App() {
  return (
    <div className="container">
      <h1>Заголовок</h1>
      <p>Параграф текста</p>
    </div>
  );
}

Почему требовался импорт React?

Поскольку после трансформации код содержал вызовы React.createElement(), переменная React должна была быть доступна в области видимости. Без импорта JavaScript-движок не знал, что такое React, и выбрасывал ошибку.

Code Example 2: Какая ошибка возникнет в первом примере? Почему?

jsx
// ❌ До React 17 — ошибка!
// ReferenceError: React is not defined
function Button() {
  return <button>Нажми меня</button>;
}
 
// ✅ До React 17 — правильно
import React from 'react';
 
function Button() {
  return <button>Нажми меня</button>;
}

Практические примеры

Старый подход (до React 17)

Code Example 3: Зачем нужен импорт React, если мы его явно не используем в коде компонента?

jsx
// Обязательный импорт React
import React from 'react';
 
// Компонент с JSX
function UserCard({ name, email }) {
  return (
    <div className="user-card">
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
}
 
export default UserCard;

Новый подход (React 17+)

Code Example 4: Почему в React 17+ можно не импортировать React для JSX? Что изменилось?

jsx
// Импорт React НЕ требуется для JSX!
function UserCard({ name, email }) {
  return (
    <div className="user-card">
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
}
 
export default UserCard;
⚠️

Если вы используете хуки или другие API React, импорт всё равно нужен — но только для конкретных функций: import { useState } from 'react'


Как работает новый JSX Transform

В React 17 появился новый способ трансформации JSX, который автоматически импортирует нужные функции:

Code Example 5: Как новый JSX transform отличается от старого? Что Babel добавляет автоматически?

jsx
function App() {
  return <h1>Привет!</h1>;
}

Преимущества нового подхода

АспектСтарый подходНовый подход (React 17+)
Импорт ReactОбязателен в каждом файлеНе нужен для JSX
Размер бандлаБольшеНемного меньше
BoilerplateБольше кодаМеньше кода
ЛинтерыКонфликты с unused importsНет проблем

Пограничные кейсы

⚠️

Даже в React 17+ импорт React нужен, если вы используете его API напрямую.

Code Example 6: В каких случаях импорт React всё ещё необходим даже в React 17+?

jsx
// Нужен импорт — используем хуки
import { useState, useEffect } from 'react';
 
function Counter() {
  const [count, setCount] = useState(0);
 
  useEffect(() => {
    document.title = `Счётчик: ${count}`;
  }, [count]);
 
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
jsx
// Нужен импорт — используем React.memo
import { memo } from 'react';
 
const ExpensiveComponent = memo(function ExpensiveComponent({ data }) {
  return <div>{/* ... */}</div>;
});

Плюсы и минусы

Плюсы нового JSX Transform

  • Чище код — меньше boilerplate
  • Меньше бандл — небольшая оптимизация размера
  • Нет конфликтов с линтерами — не нужно отключать правила для "неиспользуемых" импортов
  • Проще для новичков — одной концепцией меньше для изучения

Когда всё ещё нужен импорт React

  • Использование хуков (useState, useEffect, etc.)
  • Использование React.memo, React.forwardRef
  • Использование React.Fragment в полной форме
  • Работа с React.Children
  • Создание элементов через React.createElement напрямую

Вопросы интервьюера

Q: Зачем нужен был импорт React, если мы его явно не использовали в коде?

JSX трансформировался в вызовы React.createElement(), поэтому переменная React должна была быть в области видимости.

Q: Можно ли в React 17+ полностью не импортировать React?

Да, если файл содержит только JSX. Но для хуков и других API React импорт нужен.

Q: Как Babel понимает, какой transform использовать?

Через конфигурацию пресета @babel/preset-react с опцией runtime: 'automatic' (по умолчанию с React 17).

Q: Работает ли новый transform со старыми версиями React?

Да, новый transform был бэкпортирован в React 16.14.0, 15.7.0 и 0.14.10.


Источники

Code Example 1: JSX transformation (old approach)

❓ Во что Babel преобразует JSX? Почему требовался импорт React?

JSX (исходный код):

jsx
function App() {
  return (
    <div className="container">
      <h1>Заголовок</h1>
      <p>Параграф текста</p>
    </div>
  );
}

JavaScript (после Babel):

js
function App() {
  return React.createElement(
    'div',
    { className: 'container' },
    React.createElement('h1', null, 'Заголовок'),
    React.createElement('p', null, 'Параграф текста')
  );
}

Code Example 2: Without React import - error

❓ Какая ошибка возникнет в первом примере? Почему?

jsx
function Button() {
  return <button>Нажми меня</button>;
}
 
import React from 'react';
 
function Button() {
  return <button>Нажми меня</button>;
}

Code Example 3: Old approach (pre React 17)

❓ Зачем нужен импорт React, если мы его явно не используем в коде компонента?

jsx
import React from 'react';
 
function UserCard({ name, email }) {
  return (
    <div className="user-card">
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
}
 
export default UserCard;

Code Example 4: New approach (React 17+)

❓ Почему в React 17+ можно не импортировать React для JSX? Что изменилось?

jsx
function UserCard({ name, email }) {
  return (
    <div className="user-card">
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
}
 
export default UserCard;

Code Example 5: New JSX transform

❓ Как новый JSX transform отличается от старого? Что Babel добавляет автоматически?

JSX (исходный код):

jsx
function App() {
  return <h1>Привет!</h1>;
}

JavaScript (новый transform):

js
import { jsx as _jsx } from 'react/jsx-runtime';
 
function App() {
  return _jsx('h1', { children: 'Привет!' });
}

Code Example 6: When React import is still needed

❓ В каких случаях импорт React всё ещё необходим даже в React 17+?

jsx
import { useState, useEffect } from 'react';
 
function Counter() {
  const [count, setCount] = useState(0);
 
  useEffect(() => {
    document.title = `Счётчик: ${count}`;
  }, [count]);
 
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
jsx
import { memo } from 'react';
 
const ExpensiveComponent = memo(function ExpensiveComponent({ data }) {
  return <div>{/* ... */}</div>;
});