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 повертає контекстне значення </CodeStep> для <CodeStep data-step="1">контекст</CodeStep> ви пройшли. Щоб визначити значення контексту, React шукає в дереві компонентів і знаходить <strong>найближчого постачальника контексту вище</strong> для цього конкретного контексту.</p> <p>Щоб передати контекст до <коду>Button, обгорніть його або один з його батьківських компонентів у відповідний провайдер контексту.

function MyPage() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  );
}

function Form() {
  // ... renders buttons inside ...
}

Не має значення, скільки шарів компонентів знаходиться між постачальником та Button. Коли Button в будь-якому місці всередині Form викликає use(ThemeContext), він отримає "dark" як значення.

На відміну від useContext, <code>використовуйте можна викликати в умовних операторах та циклах на кшталт <code>if .

function HorizontalRule({ show }) {
  if (show) {
    const theme = use(ThemeContext);
    return <hr className={theme} />;
  }
  return false;
}

<code>use викликається зсередини <коду>if оператор, що дозволяє умовно читати значення з контексту.

Як і 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 як проп з Серверного компонента</CodeStep> до <CodeStep data-step="2">Клієнтський компонент</CodeStep> .</p> <pre><code data-meta="[[1, 4, "App"], [2, 2, "Message"], [3, 7, "Suspense"], [4, 8, " messagePromise", 30], [4, 5, "messagePromise"]]" class="language-js">import { fetchMessage } from '. /lib.js'; імпортуйте { Message } з './message.js'; експортуємо функцію за замовчуванням App() { const messagePromise = fetchMessage(); return ( <Suspense fallback={<p>очікування повідомлення...</p>}> <Повідомлення messagePromise={messagePromise} /> </Suspense> ); }

Клієнтський компонент Крок коду Хук. Це дозволяє використовувати Клієнтський компонент</Крок коду> щоб прочитати значення з <CodeStep data-step="4">Обіцянки</CodeStep> , який було створено серверним компонентом.</p> <pre><code data-meta="[[2, 6, "Message"], [4, 6, "messagePromise"], [4, 7, "messagePromise"], [5, 7, "use"]]" class="language-js">// message.js 'use client'; імпортувати { use } з 'react'; export function Message({ messagePromise }) { const messageContent = use(messagePromise); return <p>Ось повідомлення: {messageContent}</p>; }

Так як <code>Повідомлення загорнуто в <a href="/reference/react/Suspense"><код>Suspense , резервний варіант буде показано, доки обіцянку не буде виконано. Коли Обіцянку буде виконано, значення буде зчитано за допомогою <коду>use Хук і <код>Повідомлення компонент замінить запасний варіант Suspense.

"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, може бути відхилено. Ви можете обробляти відхилені Обіцянки одним із способів:

або
  1. Відображення помилки для користувачів з межею помилки.
  2. Надання альтернативного значення за допомогою 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, буде відхилено, ви можете скористатися <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch" target="_blank" rel="nofollow noopener noreferrer"><код>catch method.

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>
  );
}

Для використання коду обіцянки <catch метод, виклик <код>catch на об'єкті Promise. <code>catch приймає єдиний аргумент: функцію, яка приймає повідомлення про помилку як аргумент. Незалежно від того, що повертається</CodeStep> функцією, переданою в <CodeStep data-step="1"><code>catch буде використано як розв'язане значення обіцянки.


Налагодження

"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);
  // ...