Импорт и экспорт компонентов

«Магия» компонентов заключается в возможности их повторного использования. Вы можете создавать компоненты, которые состоят из других компонентов. Но по мере увеличения вложенности компонентов зачастую бывает разумным разделить их на отдельные файлы. Это повышает читаемость кода и позволяет повторно использовать компоненты в большем количестве мест.

You will learn

  • Что такое корневой компонент
  • Как импортировать и экспортировать компонент
  • Когда использовать дефолтные и именованные импорты и экспорты
  • Как импортировать и экспортировать несколько компонентов из одного файла
  • Как разделять компоненты на отдельные файлы

Файл корневого компонента

В разделе Ваш первый компонент вы создали компонент Profile и компонент Gallery, который рендерит его:

function Profile() {
  return (
    <img
      src="https://i.imgur.com/MK3eW3As.jpg"
      alt="Кэтрин Джонсон"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Восхитительные ученые</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

Эти компоненты сейчас находятся внутри файла корневого компонента, который в примере называется App.js. При использовании Create React App приложение находится в src/App.js. Однако, в зависимости от конфигурации файлов в проекте, корневой компонент может находиться в другом файле. При использовании фреймворка с маршрутизацией на основе файлов, например Next.js, корневой компонент будет разным для каждой страницы.

Экспорт и импорт компонентов

Что, если в будущем вы захотите изменить страницу и отобразить на ней список научных книг? Или расположить профили ученых в другом месте? Кажется разумным извлечь компоненты Gallery и Profile из файла корневого компонента. Это сделает их более модульными и позволит повторно использовать их в других файлах. Переместить компонент можно в три шага:

  1. Создайте новый JS файл для компонентов.
  2. Экспортируйте функциональный компонент из этого файла (используя или экспорт по умолчанию или именованный экспорт).
  3. Импортируйте компонент в файл, где вы будете его использовать (используя соответствующую технику для импорта значения по умолчанию или именованного экспорта).

В следующем примере Profile и Gallery были извлечены из App.js в новый файл Gallery.js. Теперь вы можете изменить App.js, добавив в него импорт компонента Gallery из файла Gallery.js:

import Gallery from './Gallery.js';

export default function App() {
  return (
    <Gallery />
  );
}

Обратите внимание, что код из примера теперь использует два файла компонентов:

  1. Gallery.js:
    • Содержит компонент Profile, который используется только в этом файле и не экспортируется.
    • Экспортирует компонент Gallery по умолчанию.
  2. App.js:
    • Импортирует компонент Gallery из Gallery.js по умолчанию.
    • Экспортирует корневой компонент App по умолчанию.

Note

В некоторых случаях вы можете заметить, что при импорте в именах файлов опускается расширение .js, например:

import Gallery from './Gallery';

Оба варианта ('./Gallery.js' и './Gallery') будут работать в React, хотя первый вариант ближе к тому, как работают нативные ES-модули.

Deep Dive

Экспорт по умолчанию и именованный экспорт

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

Именованные экспорты и экспорты по умолчанию

Способ, которым компонент был экспортирован, определяет способ, которым его нужно импортировать. Вы получите ошибку, если попытаетесь импортировать экспортированный по умолчанию компонент так же, как компонент с именованным экспортом! Эта таблица поможет вам разобраться:

Синтаксис экспортаКак экспортироватьКак импортировать
По умолчаниюexport default function Button() {}import Button from './Button.js';
Именованныйexport function Button() {}import { Button } from './Button.js';

При использовании импорта по умолчанию можно использовать любое имя после слова import. Например, можно написать import Banana from './Button.js', и эта запись все еще будет корректно импортировать значение по умолчанию. При использовании именованных импортов, напротив, значения должны совпадать в обоих файлах. Именно поэтому такие импорты называются именованными.

Разработчики часто используют экспорт по умолчанию, если файл экспортирует только один компонент, и именованный экспорт, если он экспортирует несколько компонентов и значений. Независимо от того, какой стиль написания кода вы предпочитаете, всегда давайте осмысленные имена вашим функциональным компонентам и файлам, которые их содержат. Не рекомендуется использовать компоненты без имен, такие как export default () => {}, поскольку это затрудняет отладку.

Экспорт и импорт нескольких компонентов из одного файла

Что, если вы хотите показывать только один компонент Profile вместо всей галереи? Компонент Profile тоже можно экспортировать. Но в файле Gallery.js уже есть экспорт по умолчанию, а в одном файле не может быть двух экспортов по умолчанию. Вы можете создать новый файл с экспортом по умолчанию или добавить именованный экспорт для компонента Profile. В файле может быть только один экспорт по умолчанию, но несколько именованных экспортов!

Note

Чтобы избежать потенциальной путаницы между дефолтными и именованными экспортами, некоторые команды предпочитают придерживаться только одного стиля (экспорт по умолчанию или именованный) или не смешивать их в одном файле. Делайте то, что подходит именно вам!

Сначала экспортируйте Profile из Gallery.js, используя именованный экспорт (без использования ключевого слова default):

export function Profile() {
// ...
}

Затем импортируйте Profile из Gallery.js в App.js, используя именованный импорт (с фигурными скобками):

import { Profile } from './Gallery.js';

Теперь вы можете отрендерить <Profile /> из компонента App:

export default function App() {
return <Profile />;
}

Теперь Gallery.js содержит два экспорта: экспорт по умолчанию Gallery и именованный экспорт Profile. App.js импортирует их оба. Попробуйте изменить <Profile /> на <Gallery /> и обратно в этом примере:

import Gallery from './Gallery.js';
import { Profile } from './Gallery.js';

export default function App() {
  return (
    <Profile />
  );
}

Теперь вы используете как именованные экспорты, так и экспорты по умолчанию:

  • Gallery.js:
    • Экспортирует компонент Profile как именованный экспорт Profile.
    • Экспортирует компонент Gallery по умолчанию.
  • App.js:
    • Импортирует компонент Profile как именованный импорт Profile из файла Gallery.js.
    • Импортирует компонент Gallery как экспорт по умолчанию из файла Gallery.js.
    • Экспортирует корневой компонент App по умолчанию.

Recap

В этом разделе вы узнали:

  • Что такое корневой компонент
  • Как импортировать и экспортировать компонент
  • Когда использовать дефолтные и именованные импорты и экспорты
  • Как экспортировать несколько компонентов из одного файла

Challenge 1 of 1:
Дальнейшее разделение компонентов

Сейчас файл Gallery.js экспортирует два компонента (Profile и Gallery), что может немного сбивать с толку.

Переместите компонент Profile в отдельный файл Profile.js, и затем изменить компонент App так, чтобы в нем друг за другом рендерились компоненты <Profile /> и <Gallery />.

Вы можете использовать либо экспорт по умолчанию, либо именованный экспорт для Profile, но убедитесь, что вы используете соответствующий синтаксис импорта как в App.js, так и в Gallery.js! Вы можете свериться с этой таблицей:

Синтаксис экспортаКак экспортироватьКак импортировать
По умолчаниюexport default function Button() {}import Button from './Button.js';
Именованныйexport function Button() {}import { Button } from './Button.js';
// Перемести меня в Profile.js!
export function Profile() {
  return (
    <img
      src="https://i.imgur.com/QIrZWGIs.jpg"
      alt="Алан Л. Харт"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Восхитительные ученые</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

После того, как вы выполните это задание с использованием одного из типов экспорта, выполните его с использованием другого типа.