use
๋ Promise๋ context์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ๋ React Hook์
๋๋ค.
const value = use(resource);
Reference
use(resource)
์ปดํฌ๋ํธ์์ Promise๋ context์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ๋ ค๋ฉด use
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
import { use } from 'react';
function MessageComponent({ messagePromise }) {
const message = use(messagePromise);
const theme = use(ThemeContext);
// ...
๋ค๋ฅธ React Hook๊ณผ ๋ฌ๋ฆฌ use
๋ if
์ ๊ฐ์ ์กฐ๊ฑด๋ฌธ๊ณผ ๋ฐ๋ณต๋ฌธ ๋ด๋ถ์์ ํธ์ถํ ์ ์์ต๋๋ค.
๋ค๋ฅธ React Hook๊ณผ ๊ฐ์ด use
๋ ์ปดํฌ๋ํธ ๋๋ Hook์์๋ง ํธ์ถํ ์ ์์ต๋๋ค.
Promise์ ํจ๊ป ํธ์ถ๋ ๋ use
Hook์ Suspense ๋ฐ error boundary์ ํตํฉ๋ฉ๋๋ค.
use
์ ์ ๋ฌ๋ Promise๊ฐ ๋ณด๋ฅ๋๋ ๋์ use
๋ฅผ ํธ์ถํ๋ ์ปดํฌ๋ํธ๋ ์ผ์ ์ค๋จ๋ฉ๋๋ค.
use
๋ฅผ ํธ์ถํ๋ ์ปดํฌ๋ํธ๊ฐ Suspense ๊ฒฝ๊ณ๋ก ๋๋ฌ์ธ์ฌ ์์ผ๋ฉด fallback์ด ํ์๋ฉ๋๋ค.
Promise๊ฐ ๋ฆฌ์กธ๋ธ๋๋ฉด Suspense fallback์ use
Hook์ด ๋ฐํํ ์ปดํฌ๋ํธ๋ก ๋์ฒด๋ฉ๋๋ค.
use
์ ์ ๋ฌ๋ Promise๊ฐ ๊ฑฐ๋ถ๋๋ฉด ๊ฐ์ฅ ๊ฐ๊น์ด Error Boundary์ fallback์ด ํ์๋ฉ๋๋ค.
๋งค๊ฐ๋ณ์
๋ฐํ๊ฐ
use
Hook์ Promise๋ context์์ ์ฐธ์กฐํ ๊ฐ์ ๋ฐํํฉ๋๋ค.
์ฃผ์ ์ฌํญ
use
Hook์ ์ปดํฌ๋ํธ๋ Hook ๋ด๋ถ์์ ํธ์ถ๋์ด์ผ ํฉ๋๋ค.- ์๋ฒ ์ปดํฌ๋ํธ์์ ๋ฐ์ดํฐ๋ฅผ fetch ํ ๋๋
use
๋ณด๋คasync
๋ฐawait
๋ฅผ ์ฌ์ฉํฉ๋๋ค. async
๋ฐawait
์await
์ด ํธ์ถ๋ ์์ ๋ถํฐ ๋ ๋๋ง์ ์์ํ๋ ๋ฐ๋ฉดuse
๋ ๋ฐ์ดํฐ๊ฐ ๋ฆฌ์กธ๋ธ๋ ํ ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋งํฉ๋๋ค.- ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ Promise๋ฅผ ์์ฑํ๋ ๊ฒ๋ณด๋ค ์๋ฒ ์ปดํฌ๋ํธ์์ Promise๋ฅผ ์์ฑํ์ฌ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ ์์ฑ๋ Promise๋ ๋ ๋๋งํ ๋๋ง๋ค ๋ค์ ์์ฑ๋ฉ๋๋ค. ์๋ฒ ์ปดํฌ๋ํธ์์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ ๋ฌ๋ Promise๋ ๋ฆฌ๋ ๋๋ง ์ ๋ฐ์ ๊ฑธ์ณ ์์ ์ ์ ๋๋ค. ์์ ํ์ธํ๊ธฐ.
์ฌ์ฉ๋ฒ
use
๋ฅผ ์ฌ์ฉํ์ฌ context ์ฐธ์กฐํ๊ธฐ
context๊ฐ use
์ ์ ๋ฌ๋๋ฉด useContext
์ ์ ์ฌํ๊ฒ ์๋ํฉ๋๋ค. useContext
๋ ์ปดํฌ๋ํธ์ ์ต์์ ์์ค์์ ํธ์ถํด์ผ ํ์ง๋ง use
๋ if
์ ๊ฐ์ ์กฐ๊ฑด๋ฌธ์ด๋ for
๊ณผ ๊ฐ์ ๋ฐ๋ณต๋ฌธ ๋ด๋ถ์์ ํธ์ถํ ์ ์์ต๋๋ค. use
๋ ์ ์ฐํ๋ฏ๋ก useContext
๋ณด๋ค ์ ํธ๋ฉ๋๋ค.
import { use } from 'react';
function Button() {
const theme = use(ThemeContext);
// ...
use
๋ ์ ๋ฌํ context์ context ๊ฐ์ ๋ฐํํฉ๋๋ค. context ๊ฐ์ ๊ฒฐ์ ํ๊ธฐ ์ํด React๋ ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ๊ฒ์ํ๊ณ ์์์ ๊ฐ์ฅ ๊ฐ๊น์ด context provider๋ฅผ ์ฐพ์ต๋๋ค.
context๋ฅผ Button
์ ์ ๋ฌํ๋ ค๋ฉด Button
๋๋ ์์ ์ปดํฌ๋ํธ ์ค ํ๋๋ฅผ context provider๋ก ๋ํํฉ๋๋ค.
function MyPage() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
);
}
function Form() {
// ... ๋ฒํผ ๋ ๋๋ง ...
}
provider์ Button
์ฌ์ด์ ์ผ๋ง๋ ๋ง์ ์ปดํฌ๋ํธ๊ฐ ์๋์ง๋ ์ค์ํ์ง ์์ต๋๋ค. Form
๋ด๋ถ์ ์ด๋ ๊ณณ์ด๋ Button
์ด use(ThemeContext)
๋ฅผ ํธ์ถํ๋ฉด "dark"
๋ฅผ ๊ฐ์ผ๋ก ๋ฐ์ต๋๋ค
useContext
์ ๋ฌ๋ฆฌ use
๋ if
์ ๊ฐ์ ์กฐ๊ฑด๋ฌธ๊ณผ ๋ฐ๋ณต๋ฌธ ๋ด๋ถ์์ ํธ์ถํ ์ ์์ต๋๋ค.
function HorizontalRule({ show }) {
if (show) {
const theme = use(ThemeContext);
return <hr className={theme} />;
}
return false;
}
use
๋ if
๋ด๋ถ์์ ํธ์ถ๋๋ฏ๋ก 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 }
์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐํ๊ธฐ
์๋ฒ ์ปดํฌ๋ํธ์์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก Promise prop์ ์ ๋ฌํ์ฌ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ ์ ์์ต๋๋ค.
import { fetchMessage } from './lib.js';
import { Message } from './message.js';
export default function App() {
const messagePromise = fetchMessage();
return (
<Suspense fallback={<p>waiting for message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}
ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ prop์ผ๋ก ๋ฐ์ Promise๋ฅผ use
Hook์ ์ ๋ฌํฉ๋๋ค.
Client Component๋ ์๋ฒ ์ปดํฌ๋ํธ๊ฐ ์ฒ์์ ์์ฑํ Promise์์ ๊ฐ์ ์ฝ์ ์ ์์ต๋๋ค.
// message.js
'use client';
import { use } from 'react';
export function Message({ messagePromise }) {
const messageContent = use(messagePromise);
return <p>Here is the message: {messageContent}</p>;
}
Message
๋ Suspense
๋ก ๋ํ๋์ด ์์ผ๋ฏ๋ก Promise๊ฐ ๋ฆฌ์กธ๋ธ๋ ๋๊น์ง fallback์ด ํ์๋ฉ๋๋ค. Promise๊ฐ ๋ฆฌ์กธ๋ธ๋๋ฉด use
Hook์ด ๊ฐ์ ์ฐธ์กฐํ๊ณ Message
์ปดํฌ๋ํธ๊ฐ Suspense fallback์ ๋์ฒดํฉ๋๋ค.
"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> ); }
Deep Dive
Promise๋ ์๋ฒ ์ปดํฌ๋ํธ์์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ ๋ฌ๋ ์ ์์ผ๋ฉฐ use
Hook์ ํตํด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ ๋ฆฌ์กธ๋ธ๋ฉ๋๋ค. ๋ํ ์๋ฒ ์ปดํฌ๋ํธ์์ await
์ ์ฌ์ฉํ์ฌ Promise๋ฅผ ๋ฆฌ์กธ๋ธํ๊ณ ๋ฐ์ดํฐ๋ฅผ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ prop
์ผ๋ก ์ ๋ฌํ๋ ๋ฐฉ๋ฒ๋ ์กด์ฌํฉ๋๋ค.
export default function App() {
const messageContent = await fetchMessage();
return <Message messageContent={messageContent} />
}
ํ์ง๋ง ์๋ฒ ์ปดํฌ๋ํธ์์ await
์ ์ฌ์ฉํ๋ฉด await
๋ฌธ์ด ์๋ฃ๋ ๋๊น์ง ๋ ๋๋ง์ด ์ฐจ๋จ๋ฉ๋๋ค. ์๋ฒ ์ปดํฌ๋ํธ์์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก Promise๋ฅผ prop์ผ๋ก ์ ๋ฌํ๋ฉด Promise๊ฐ ์๋ฒ ์ปดํฌ๋ํธ์ ๋ ๋๋ง์ ์ฐจ๋จํ๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๊ฑฐ๋ถ๋ Promise ์ฒ๋ฆฌํ๊ธฐ
๊ฒฝ์ฐ์ ๋ฐ๋ผ use
์ ์ ๋ฌ๋ Promise๊ฐ ๊ฑฐ๋ถ๋ ์ ์์ต๋๋ค. ๊ฑฐ๋ถ๋ ํ๋ก๋ฏธ์ค๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ 2๊ฐ์ง๊ฐ ์กด์ฌํฉ๋๋ค.
error boudary๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ฅ ํ์ํ๊ธฐ
Promise๊ฐ ๊ฑฐ๋ถ๋ ๋ ์ค๋ฅ๋ฅผ ํ์ํ๊ณ ์ถ๋ค๋ฉด error boundary๋ฅผ ์ฌ์ฉํฉ๋๋ค. error boundary๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด use
Hook์ ํธ์ถํ๋ ์ปดํฌ๋ํธ๋ฅผ error boundary๋ก ๋ํํฉ๋๋ค. use
์ ์ ๋ฌ๋ Promise๊ฐ ๊ฑฐ๋ถ๋๋ฉด error boundary์ ๋ํ fallback์ด ํ์๋ฉ๋๋ค.
"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>; }
Promise.catch
๋ฅผ ์ฌ์ฉํ์ฌ ๋์ฒด ๊ฐ ์ ๊ณตํ๊ธฐ
use
์ ์ ๋ฌ๋ Promise๊ฐ ๊ฑฐ๋ถ๋ ๋ ๋์ฒด ๊ฐ์ ์ ๊ณตํ๋ ค๋ฉด Promise์ catch
๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
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>
);
}
Promise์ catch
๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด Promise ๊ฐ์ฒด์์ catch
๋ฅผ ํธ์ถํฉ๋๋ค. catch
๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ธ์๋ก ๋ฐ๋ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ์ต๋๋ค. catch
์ ์ ๋ฌ๋ ํจ์๊ฐ ๋ฐํํ๋ํ๋ ๊ฐ์ ๋ชจ๋ Promise์ ๋ฆฌ์กธ๋ธ ๊ฐ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
ํธ๋ฌ๋ธ์ํ
โSuspense Exception: This is not a real error!โ
React ์ปดํฌ๋ํธ ๋๋ hook ํจ์ ์ธ๋ถ์์, ํน์ try-catch ๋ธ๋ก์์ use
๋ฅผ ํธ์ถํ๊ณ ์๋ ๊ฒฝ์ฐ์
๋๋ค. try-catch ๋ธ๋ก ๋ด์์ use
๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ ์ปดํฌ๋ํธ๋ฅผ error boundary๋ก ๋ํํ๊ฑฐ๋ Promise์ catch
๋ฅผ ํธ์ถํ์ฌ ์๋ฌ๋ฅผ ๋ฐ๊ฒฌํ๊ณ Promise๋ฅผ ๋ค๋ฅธ ๊ฐ์ผ๋ก ๋ฆฌ์กธ๋ธํฉ๋๋ค. ์์ ํ์ธํ๊ธฐ
React ์ปดํฌ๋ํธ๋ Hook ํจ์ ์ธ๋ถ์์ use
๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ use
ํธ์ถ์ React ์ปดํฌ๋ํธ๋ Hook ํจ์๋ก ์ด๋ํฉ๋๋ค.
function MessageComponent({messagePromise}) {
function download() {
// โ `use`๋ฅผ ํธ์ถํ๋ ํจ์๊ฐ ์ปดํฌ๋ํธ๋ hook์ด ์๋๋๋ค.
const message = use(messagePromise);
// ...
์ปดํฌ๋ํธ ํด๋ก์ ์ธ๋ถ์์ use
๋ฅผ ํธ์ถํฉ๋๋ค. ์ฌ๊ธฐ์ use
๋ฅผ ํธ์ถํ๋ ํจ์๋ ์ปดํฌ๋ํธ ๋๋ Hook์
๋๋ค.
function MessageComponent({messagePromise}) {
// โ
`use`๊ฐ ์ปดํฌ๋ํธ์์ ํธ์ถ๋๊ณ ์์ต๋๋ค.
const message = use(messagePromise);
// ...