use
Хук use
наразі доступний лише в Canary та експериментальних каналах React. Дізнайтеся більше про канали релізів React тут.
use
- це хук React, який дозволяє читати значення ресурсу, наприклад, обіцянку або контекст.
const value = use(resource);
Довідник
use(resource)
Викличте використання
у вашому компоненті, щоб прочитати значення ресурсу, такого як обіцянка або контекст.
import { use } from 'react';
function MessageComponent({ messagePromise }) {
const message = use(messagePromise);
const theme = use(ThemeContext);
// ...
На відміну від інших хуків React, use
можна викликати в циклах та умовних операторах, таких як if
. Як і інші хуки React, функція, яка викликає use
, повинна бути компонентом або хуком.
При виклику з обіцянкою, хук use
інтегрується з Suspense
та межами помилки. Компонент, що викликає use
, призупиняє , поки Обіцянка, передана до use
, перебуває у стані очікування. Якщо компонент, який викликає use
, обгорнуто межею призупинення, буде показано запасний варіант. Після того, як обіцянку буде виконано, запасний варіант Suspense буде замінено відрендереними компонентами, що використовують дані, повернуті хуком use
. Якщо Обіцянку, передану до use
, відхилено, буде показано резервний варіант найближчої межі помилки.
Дивіться більше прикладів нижче.
Параметри
джерело
: це джерело даних, з якого ви хочете прочитати значення. Джерело може бути обіцянкою або контекстом.
Повернення
Хук use
повертає значення, яке було прочитано з ресурсу, наприклад, роздільне значення Promise або context.
Застереження
- Хук
use
має бути викликаний всередині компонента або хука. - Під час отримання даних у серверному компоненті надавайте перевагу
синхронізації
таочікуванню
надвикористанням
.async
таawait
підхоплюють рендеринг з точки, де було викликаноawait
, тоді якuse
повторно рендерить компонент після розв'язання даних. - Надавайте перевагу створенню обіцянок у Серверних компонентах та передачі їх до Клієнтських компонентів перед створенням обіцянок у Клієнтських компонентах. Обіцянки, створені у клієнтських компонентах, відтворюються під час кожного рендеру. Обіцянки, передані з серверного компонента до клієнтського, є стабільними під час повторного рендерингу. Дивіться цей приклад.
Використання
Читання контексту за допомогою використання
Коли контекст передається до використання
, він працює подібно до useContext
. У той час як useContext
слід викликати на верхньому рівні вашого компонента, use
можна викликати всередині умов, таких як if
і циклів, таких як for
. використання
є кращим за useContext
, оскільки воно є більш гнучким.
import { use } from 'react';
function Button() {
const theme = use(ThemeContext);
// ...
use
повертає
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}
function Form() {
// ... renders buttons inside ...
}
Не має значення, скільки шарів компонентів знаходиться між постачальником та Button
. Коли Button
в будь-якому місці всередині Form
викликає use(ThemeContext)
, він отримає "dark"
як значення.
На відміну від useContext
,
function HorizontalRule({ show }) {
if (show) {
const theme = use(ThemeContext);
return <hr className={theme} />;
}
return false;
}
Як і useContext
, use(context)
завжди шукає найближчого постачальника контексту над компонентом, який його викликає. Він шукає вгору і не враховує постачальників контексту у компоненті, з якого ви викликаєте use(context)
.
import { createContext, use } from 'react';
const ThemeContext = createContext(null);
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
)
}
function Form() {
return (
<Panel title="Welcome">
<Button show={true}>Sign up</Button>
<Button show={false}>Log in</Button>
</Panel>
);
}
function Panel({ title, children }) {
const theme = use(ThemeContext);
const className = 'panel-' + theme;
return (
<section className={className}>
<h1>{title}</h1>
{children}
</section>
)
}
function Button({ show, children }) {
if (show) {
const theme = use(ThemeContext);
const className = 'button-' + theme;
return (
<button className={className}>
{children}
</button>
);
}
return false
}
.panel-light,
.panel-dark {
border: 1px solid black;
border-radius: 4px;
padding: 20px;
}
.panel-light {
color: #222;
background: #fff;
}
.panel-dark {
color: #fff;
background: rgb(23, 32, 42);
}
.button-light,
.button-dark {
border: 1px solid #777;
padding: 5px;
margin-right: 10px;
margin-top: 10px;
}
.button-dark {
background: #222;
color: #fff;
}
.button-light {
background: #fff;
color: #222;
}
{
"dependencies": {
"react": "18.3.0-canary-9377e1010-20230712",
"react-dom": "18.3.0-canary-9377e1010-20230712",
"react-scripts": "^5.0.0"
},
"main": "/index.js"
}
Потокова передача даних від сервера до клієнта
Дані можна передавати з сервера до клієнта, передавши Promise як проп з Клієнтський компонент Так як
"use client";
import { use, Suspense } from "react";
function Message({ messagePromise }) {
const messageContent = use(messagePromise);
return <p>Here is the message: {messageContent}</p>;
}
export function MessageContainer({ messagePromise }) {
return (
<Suspense fallback={<p>⌛Downloading message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}
import { useState } from "react";
import { MessageContainer } from "./message.js";
function fetchMessage() {
return new Promise((resolve) => setTimeout(resolve, 1000, "⚛️"));
}
export default function App() {
const [messagePromise, setMessagePromise] = useState(null);
const [show, setShow] = useState(false);
function download() {
setMessagePromise(fetchMessage());
setShow(true);
}
if (show) {
return <MessageContainer messagePromise={messagePromise} />;
} else {
return <button onClick={download}>Download message</button>;
}
}
// TODO: update to import from stable
// react instead of canary once the `use`
// Hook is in a stable release of React
import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';
// TODO: update this example to use
// the Codesandbox Server Component
// demo environment once it is created
import App from './App';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
);
{
"dependencies": {
"react": "18.3.0-canary-9377e1010-20230712",
"react-dom": "18.3.0-canary-9377e1010-20230712",
"react-scripts": "^5.0.0"
},
"main": "/index.js"
}
При передачі обіцянки від серверного компонента до клієнтського компонента, її розв'язане значення має бути серіалізованим для передачі між сервером та клієнтом. Такі типи даних, як функції, не можна серіалізувати, і вони не можуть бути результуючим значенням такої Обіцянки.
Чи слід обробляти обіцянку у серверному або клієнтському компоненті?
Обіцянка може бути передана з серверного компонента до клієнтського компонента та оброблена у клієнтському компоненті за допомогою хука use
. Ви також можете виконати обробку обіцянки у серверному компоненті за допомогою await
і передати необхідні дані клієнтському компоненту як проп.
export default async function App() {
const messageContent = await fetchMessage();
return <Message messageContent={messageContent} />
}
Але використання await
у Компоненті сервера заблокує його рендеринг до завершення оператора await
. Передача Обіцянки з серверного компонента до клієнтського не дозволяє Обіцянці блокувати рендеринг серверного компонента.
Робота з відхиленими обіцянками
У деяких випадках обіцянку, передану до use
, може бути відхилено. Ви можете обробляти відхилені Обіцянки одним із способів:
- Відображення помилки для користувачів з межею помилки.
- Надання альтернативного значення за допомогою
Promise.catch
використання
не може бути викликано у блоці з перехопленням. Замість блоку перехоплення обегоніть ваш компонент у межу помилки, або надайте альтернативне значення для використання з методом обіцянки .catch
.
Відображення помилки для користувачів з межею помилки
Якщо ви хочете показувати користувачам помилку, коли обіцянку відхилено, ви можете використати межу помилки. Щоб використати межу помилки, обгорніть компонент, в якому ви викликаєте хук use
, у межу помилки. Якщо обіцянку, передану use
, буде відхилено, буде показано запасний варіант для межі помилки.
"use client";
import { use, Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
export function MessageContainer({ messagePromise }) {
return (
<ErrorBoundary fallback={<p>⚠️Something went wrong</p>}>
<Suspense fallback={<p>⌛Downloading message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
</ErrorBoundary>
);
}
function Message({ messagePromise }) {
const content = use(messagePromise);
return <p>Here is the message: {content}</p>;
}
import { useState } from "react";
import { MessageContainer } from "./message.js";
function fetchMessage() {
return new Promise((resolve, reject) => setTimeout(reject, 1000));
}
export default function App() {
const [messagePromise, setMessagePromise] = useState(null);
const [show, setShow] = useState(false);
function download() {
setMessagePromise(fetchMessage());
setShow(true);
}
if (show) {
return <MessageContainer messagePromise={messagePromise} />;
} else {
return <button onClick={download}>Download message</button>;
}
}
// TODO: update to import from stable
// react instead of canary once the `use`
// Hook is in a stable release of React
import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';
// TODO: update this example to use
// the Codesandbox Server Component
// demo environment once it is created
import App from './App';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
);
{
"dependencies": {
"react": "18.3.0-canary-9377e1010-20230712",
"react-dom": "18.3.0-canary-9377e1010-20230712",
"react-scripts": "^5.0.0",
"react-error-boundary": "4.0.3"
},
"main": "/index.js"
}
Надання альтернативного значення за допомогою Promise.catch
Якщо ви хочете надати альтернативне значення, коли обіцянку, передану до use
, буде відхилено, ви можете скористатися
import { Message } from './message.js';
export default function App() {
const messagePromise = new Promise((resolve, reject) => {
reject();
}).catch(() => {
return "no new message found.";
});
return (
<Suspense fallback={<p>waiting for message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}
Для використання коду обіцянки
Налагодження
"Suspense Exception: Це не справжня помилка!"
.Ви або викликаєте use
поза React-компонентом чи функцією хука, або викликаєте use
у блоці try-catch. Якщо ви викликаєте use
у блоці try-catch, обгорніть ваш компонент у межу помилки або викличте обіцянки catch
, щоб перехопити помилку і вирішити обіцянку з іншим значенням. Дивіться ці приклади.
Якщо ви викликаєте use
поза React-компонентом або функцією хука, перемістіть виклик use
до React-компонента або функції хука.
function MessageComponent({messagePromise}) {
function download() {
// ❌ the function calling `use` is not a Component or Hook
const message = use(messagePromise);
// ...
Натомість, викликайте use
поза будь-яким закриттям компонента, де функція, яка викликає use
є компонентом або хуком.
function MessageComponent({messagePromise}) {
// ✅ `use` is being called from a component.
const message = use(messagePromise);
// ...