'use client'
¶
Canary
'use client'
необходим только в том случае, если вы используете React Server Components или создаете совместимую с ними библиотеку.
'use client'
позволяет отметить, какой код выполняется на клиенте.
Справочник¶
'use client'
¶
Добавьте 'use client'
в верхней части файла, чтобы отметить модуль и его транзитивные зависимости как клиентский код.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Когда файл, помеченный директивой 'use client'
, импортируется из серверного компонента, совместимые бандлеры будут рассматривать импорт модуля как границу между кодом, выполняемым на сервере, и кодом, выполняемым на клиенте.
Будучи зависимостями RichTextEditor
, formatDate
и Button
также будут оцениваться на клиенте, независимо от того, содержат ли их модули директиву 'use client'
. Обратите внимание, что один модуль может оцениваться на сервере при импорте из серверного кода и на клиенте при импорте из клиентского кода.
Предостережения
'use client'
должно находиться в самом начале файла, выше любого импорта или другого кода (комментарии допускаются). Они должны быть написаны с одинарными или двойными кавычками, но не с обратными знаками.- Если модуль
'use client'
импортируется из другого клиентского модуля, директива не имеет силы. - Если модуль компонента содержит директиву
'use client'
, то любое использование этого компонента гарантированно является клиентским компонентом. Однако компонент может быть оценен на клиенте, даже если он не содержит директивы'use client'
.- Компонент считается клиентским, если он определен в модуле с директивой
'use client'
или является транзитивной зависимостью модуля, содержащего директиву'use client'
. В противном случае он является серверным компонентом.
- Компонент считается клиентским, если он определен в модуле с директивой
- Код, помеченный для использования клиентом, не ограничивается компонентами. Весь код, входящий в поддерево модулей Client, отправляется клиенту и выполняется им.
- Когда модуль, работающий с сервером, импортирует значения из модуля
'use client'
, эти значения должны быть либо компонентами React, либо поддерживаемыми сериализуемыми значениями prop для передачи в клиентский компонент. При любом другом варианте использования будет возникать исключение.
Как 'use client'
помечает клиентский код¶
В приложениях React компоненты часто разделяются на отдельные файлы, или модули.
Для приложений, использующих компоненты React Server Components, приложение по умолчанию рендерится на сервере. 'use client'
вводит границу сервер-клиент в дерево зависимостей модулей, фактически создавая поддерево модулей Client.
Чтобы лучше проиллюстрировать это, рассмотрим следующее приложение React Server Components.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 |
|
1 2 3 4 5 |
|
В дереве зависимостей модулей этого примера приложения директива 'use client'
в InspirationGenerator.js
помечает этот модуль и все его транзитивные зависимости как модули Client. Поддерево, начинающееся с InspirationGenerator.js
, теперь помечено как Client modules.
'use client'
сегментирует дерево зависимостей модулей приложения React Server Components, помечая InspirationGenerator.js
и все его зависимости как client-rendered.
Во время рендеринга фреймворк отрендерит корневой компонент и продолжит движение по дереву рендеринга, отказываясь от оценки любого кода, импортированного из кода, отмеченного клиентом.
Затем часть дерева рендеринга, отрендеренная сервером, отправляется клиенту. Клиент, загрузив свой клиентский код, завершает рендеринг оставшейся части дерева.
Дерево рендеринга для приложения React Server Components. InspirationGenerator
и его дочерний компонент FancyText
являются компонентами, экспортированными из клиентского кода и считаются клиентскими компонентами.
Мы вводим следующие определения:
- Клиентские компоненты - это компоненты в дереве рендеринга, которые отображаются на клиенте.
- Серверные компоненты - это компоненты в дереве рендеринга, которые отображаются на сервере.
Работая с примером приложения, App
, FancyText
и Copyright
рендерятся на сервере и считаются серверными компонентами. Поскольку InspirationGenerator.js
и его транзитивные зависимости помечены как клиентский код, компонент InspirationGenerator
и его дочерний компонент FancyText
являются клиентскими компонентами.
Как FancyText
является одновременно серверным и клиентским компонентом?¶
Согласно приведенным выше определениям, компонент FancyText
является одновременно серверным и клиентским компонентом, как такое может быть?
Во-первых, давайте уточним, что термин "компонент" не очень точен. Вот только два варианта понимания "компонента":
-
"Компонент" может относиться к определению компонента. В большинстве случаев это будет функция.
1 2 3 4
// This is a definition of a component function MyComponent() { return <p>My Component</p>; }
-
"Компонент" также может относиться к компонентному использованию его определения.
1 2 3 4 5 6
import MyComponent from './MyComponent'; function App() { // This is a usage of a component return <MyComponent />; }
Часто неточность не имеет значения при объяснении концепций, но в данном случае она имеет значение.
Когда мы говорим о серверных или клиентских компонентах, мы имеем в виду использование компонентов.
- Если компонент определен в модуле с директивой
'use client'
, или компонент импортируется и вызывается в клиентском компоненте, то использование компонента - это клиентский компонент. - В противном случае используется серверный компонент.
Дерево рендеринга иллюстрирует использование компонентов.
Возвращаясь к вопросу о FancyText
, мы видим, что в определении компонента нет директивы 'use client'
и у него есть два варианта использования.
Использование FancyText
в качестве дочернего компонента App
, маркирует это использование как серверный компонент. Когда FancyText
импортируется и вызывается в InspirationGenerator
, это использование FancyText
является клиентским компонентом, поскольку InspirationGenerator
содержит директиву 'use client'
.
Это означает, что определение компонента для FancyText
будет оцениваться на сервере, а также загружаться клиентом для отображения его использования в качестве клиентского компонента.
Почему Copyright
является серверным компонентом?¶
Поскольку Copyright
отображается как дочерний компонент клиентского компонента InspirationGenerator
, вы можете быть удивлены, что он является серверным компонентом.
Вспомните, что 'use client'
определяет границу между серверным и клиентским кодом на дереве зависимостей модуля, а не на дереве рендеринга.
'use client'
определяет границу между серверным и клиентским кодом в дереве зависимостей модуля.
В дереве зависимостей модулей мы видим, что App.js
импортирует и вызывает Copyright
из модуля Copyright.js
. Поскольку Copyright.js
не содержит директивы 'use client'
, использование компонента отображается на сервере. Компонент App
отображается на сервере, так как он является корневым компонентом.
Клиентские компоненты могут рендерить серверные компоненты, потому что вы можете передавать JSX в качестве реквизита. В данном случае InspirationGenerator
получает Copyright
в качестве children
. Однако модуль InspirationGenerator
никогда напрямую не импортирует модуль Copyright
и не вызывает компонент, все это делает App
. Фактически, компонент Copyright
полностью выполняется до того, как InspirationGenerator
начинает рендеринг.
Отсюда следует вывод, что отношения рендеринга между компонентами типа "родитель-ребенок" не гарантируют одинакового окружения рендеринга.
Когда использовать 'use client'
¶
С помощью 'use client'
вы можете определить, когда компоненты являются клиентскими компонентами. Поскольку серверные компоненты используются по умолчанию, здесь приводится краткий обзор преимуществ и ограничений серверных компонентов, чтобы определить, когда вам нужно пометить что-то как клиентское.
Для простоты мы говорим о серверных компонентах, но те же принципы применимы ко всему коду в вашем приложении, который выполняется на сервере.
Преимущества серверных компонентов¶
- Серверные компоненты позволяют сократить объем кода, отправляемого и выполняемого клиентом. Только клиентские модули собираются и оцениваются клиентом.
- Серверные компоненты выигрывают от работы на сервере. Они получают доступ к локальной файловой системе и могут работать с низкой задержкой при получении данных и сетевых запросах.
Ограничения серверных компонентов¶
- Серверные компоненты не могут поддерживать взаимодействие, поскольку обработчики событий должны быть зарегистрированы и вызваны клиентом.
- Например, обработчики событий типа
onClick
могут быть определены только в клиентских компонентах.
- Например, обработчики событий типа
- Серверные компоненты не могут использовать большинство хуков.
- Когда серверные компоненты отрисовываются, их вывод - это, по сути, список компонентов для отрисовки клиентом. Серверные компоненты не сохраняются в памяти после рендеринга и не могут иметь собственного состояния.
Сериализуемые типы, возвращаемые серверными компонентами¶
Как и в любом приложении React, родительские компоненты передают данные дочерним компонентам. Поскольку они отображаются в разных средах, передача данных от серверного компонента к клиентскому компоненту требует особого внимания.
Значения реквизитов, передаваемые от серверного компонента к клиентскому компоненту, должны быть сериализуемыми.
К сериализуемым реквизитам относятся:
- Примитивы
- Iterables, содержащие сериализуемые значения
- Date
- Обычные объекты: созданные с помощью инициализаторов объектов, с сериализуемыми свойствами
- Функции, являющиеся Действиями сервера
- Элементы клиентского или серверного компонента (JSX)
- Promises
Примечательно, что не поддерживаются:
- Функции, которые не экспортируются из модулей с клиентской разметкой или не помечены
'use server'
- Классы
- Объекты, являющиеся экземплярами любого класса (кроме упомянутых встроенных) или объекты с нулевым прототипом
- Символы, не зарегистрированные глобально, например,
Symbol('mySymbol')
.
Использование¶
Построение с интерактивностью и состоянием¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Поскольку Counter
требует как хук useState
, так и обработчики событий для увеличения или уменьшения значения, этот компонент должен быть клиентским компонентом и потребует директивы 'use client'
в верхней части.
В отличие от этого, компоненту, который отображает пользовательский интерфейс без взаимодействия, не нужно быть клиентским компонентом.
1 2 3 4 5 6 7 8 9 |
|
Например, родительский компонент Counter
, CounterContainer
, не требует 'use client'
, поскольку он не является интерактивным и не использует состояние. Кроме того, CounterContainer
должен быть серверным компонентом, поскольку он читает из локальной файловой системы на сервере, что возможно только в серверном компоненте.
Существуют также компоненты, которые не используют никаких функций, предназначенных только для сервера или клиента, и могут быть независимы от того, где они отображаются. В нашем предыдущем примере одним из таких компонентов является FancyText
.
1 2 3 4 5 6 7 |
|
В этом случае мы не добавляем директиву 'use client'
, в результате чего при обращении к серверному компоненту в браузер отправляется вывод FancyText
(а не его исходный код). Как было показано в предыдущем примере приложения Inspirations, FancyText
используется как серверный или клиентский компонент, в зависимости от того, где он импортируется и используется.
Но если HTML-вывод FancyText
велик по отношению к его исходному коду (включая зависимости), было бы эффективнее заставить его всегда быть клиентским компонентом. Компоненты, возвращающие длинную строку пути к SVG, - это один из случаев, когда может быть эффективнее заставить компонент быть клиентским компонентом.
Использование клиентских API¶
Ваше приложение React может использовать специфические клиентские API, такие как API браузера для веб-хранилища, работы с аудио и видео, аппаратного обеспечения устройства, среди других.
В этом примере компонент использует DOM APIs для манипулирования элементом canvas
. Поскольку эти API доступны только в браузере, он должен быть помечен как клиентский компонент.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Использование сторонних библиотек¶
Часто в приложениях на React вы используете сторонние библиотеки для работы с общими шаблонами пользовательского интерфейса или логикой.
Эти библиотеки могут опираться на хуки компонентов или клиентские API. Сторонние компоненты, использующие любой из следующих API React, должны запускаться на клиенте:
- createContext
react
иreact-dom
Hooks, за исключениемuse
иuseId
- forwardRef
- memo
- startTransition
- Если они используют клиентские API, например, вставку DOM или нативные представления платформы
Если эти библиотеки были обновлены для совместимости с React Server Components, то они уже будут содержать собственные маркеры 'use client'
, что позволит вам использовать их непосредственно из ваших серверных компонентов. Если библиотека не была обновлена, или компоненту нужны такие параметры, как обработчики событий, которые могут быть указаны только на клиенте, вам может потребоваться добавить собственный файл клиентского компонента между сторонним клиентским компонентом и вашим серверным компонентом, где вы хотите его использовать.
Источник — https://react.dev/reference/rsc/use-client