Logo
Hyunsu Blog
peep

๐Ÿ“†Published :Jan 25, 2024 โ€ข

๐Ÿ“†Updated :Jan 25, 2024 โ€ข

โ˜•๏ธ2min

next12 ์—์„œ relay๋ฅผ ์–น์œผ๋ฉด์„œ ์ƒ๊ธด Suspense ์ด์Šˆ ํ•ด๊ฒฐ๊ธฐ

์ด์Šˆ : ReactDOMServer does not yet support Suspense

issue1

์ด๋ ‡๊ฒŒ Next.js์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚˜์˜ค๊ณ  ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋œ ๊ทผ์›์ง€๋ฅผ ์•Œ๋ ค์ค€๋‹ค๋ฉด, ๋””๋ฒ„๊น…์˜ ๊ธฐ๋ฒ•์ค‘ ์—ญ์ถ”์ ์— ์˜ํ•œ ๋””๋ฒ„๊น…(Debugging by backtracking) ์œผ๋กœ ๊ฐ€๋Š” ๊ฒƒ์ด ํ•ด๊ฒฐํ•  ํ™•๋ฅ ์ด ๊ฐ€์žฅ ๋†’์Šต๋‹ˆ๋‹ค.

์‹คํ–‰ํ•œ ํŽ˜์ด์ง€์˜ ์†Œ์Šค์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

function Relay (props: RelayProps) { const data = useLazyLoadQuery(RelayQuery, {}); console.log(data) return ( <div> <h1>Relay</h1> </div> ); } const RelayQuery = graphql` query relayQuery { ping } `; export default Relay;

์—๋Ÿฌ ๋ฉ”์‹œ์ง€์— ๋ช…์‹œ๋œ ReactDom Server ๋งŽ์ด ๋“ค์–ด๋ดค์ง€๋งŒ, ์–ด๋–ค ์ผ์„ ํ• ๊นŒ์š”?

Server React DOM APIs โ€“ React

The react-dom/server APIs let you render React components to HTML on the server. These APIs are only used on the server at the top level of your app to generate the initial HTML. A framework may call them for you. Most of your components donโ€™t need to import or use them. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด "react-dom/server" API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Ÿฌํ•œ API๋Š” ์ฃผ๋กœ ์•ฑ์˜ ์ดˆ๊ธฐ HTML์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ํ™œ์šฉ๋œ๋‹ค๋Š” ๋‚ด์šฉ์„ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด๋Ÿฌํ•œ API๋“ค์„ ๋Œ€์‹  ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋Œ€๋ถ€๋ถ„์˜ React ์ปดํฌ๋„ŒํŠธ๋Š” ์ด API๋“ค์„ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

ReactDomServer๋Š” ๊ณต์‹๋ฌธ์„œ์—์„œ ์„ค๋ช…ํ•œ๋Œ€๋กœ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด๋Ÿฐ API๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

ReactDOMServer๋Š” ๋ˆ„๊ฐ€ ํ˜ธ์ถœ ํ•˜๋Š” ๊ฑธ๊นŒ์š”?

์—๋Ÿฌ๋ฅผ ์ถ”์ ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

react-dom ๋ชจ๋“ˆ์˜ ReactDOMServerRenderer์—์„œ ํ˜ธ์ถœ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Untitled

Untitled

๊ทธ๋Ÿฐ๋ฐ ์—ฌ๋Ÿฌ๊ตฐ๋ฐ์—์„œ ํŠธ๋ฆฌ๊ฑฐ ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์—๋Ÿฌ๊ฐ€ ์ •ํ™•ํžˆ ์–ด๋Š ๋ถ€๋ถ„์—์„œ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ํ•˜๋Š”์ง€ ์˜ˆ์ธก ํ•  ์ˆ˜ ์—†์–ด ์ด๋ ‡๊ฒŒ 1111, 2222, 3333 ์œผ๋กœ ์ˆซ์ž๋ฅผ ๋„ฃ์–ด๋‘๊ณ  ๋‹ค์‹œ ์‹คํ–‰ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Untitled

๊ทธ๋žฌ๋”๋‹ˆ 1111 ์—์„œ ๊ฐ์ง€๊ฐ€ ๋˜์—ˆ๋„ค์š”!

Untitled

์ •ํ™•ํ•œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

Untitled

์ œ๊ฐ€ ์ดํ•ดํ•œ ๋Œ€๋กœ ํ•ด์„์„ ํ•ด๋ณด์ž๋ฉด this.render()ํ•จ์ˆ˜ ํ˜ธ์ถœ์‹œ try.catch ๋ฌธ์— ์˜ํ•ด ์—๋Ÿฌ๊ฐ€ ๊ฐ์ง€๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฐ€ ๋งˆ์ฃผํ•œ ์—๋Ÿฌ๋Š” enableSuspenseServerRenderer๊ฐ€ false์ผ ๋•Œ ๊ทธ๋ฆฌ๊ณ  !false ์ฆ‰ true์ผ ๋•Œ ์ด ์—๋Ÿฌ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๋‹จ์„œ๋Š” enableSuspenseServerRenderer ์ด false๋ผ์„œ ์ƒ๊ธด ๊ฑฐ๋ผ๊ณ  ์ถ”์ธกํ•  ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”!

enableSuspenseServerRenderer ์ด ์นœ๊ตฌ๋Š” ์–ด๋””์„œ ์–ด๋–ป๊ฒŒ ๊ฐ’์ด ๋ณ€๊ฒฝ๋ ๊นŒ์š”?

์ฐพ์•„๋ณด๋‹ˆ ์–ด๋””์—๋„ ์‚ฌ์šฉ๋˜๋Š” ๊ณณ์ด ์—†๊ณ  ์ด๋ ‡๊ฒŒ default๊ฐ’์œผ๋กœ false๋ฅผ ๊ฐ€์ง„ ๋ณ€์ˆ˜๋งŒ ์ •์˜๋˜์–ด์žˆ๋„ค์š”.

๊ทธ๋Ÿผ ์ด ํ•จ์ˆ˜์— ๋“ค์–ด์˜ค๋ฉด enableSuspenseServerRenderer ๋Š” ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์œผ๋กœ ์ง์ž‘ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Untitled

๊ทธ๋Ÿผ ์ €์˜ ์—๋Ÿฌ๋Š” ์• ์ดˆ์— enableSuspenseServerRenderer๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ReactDomSERVER๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณธ๋‹ค๋ฉด, ๊ทผ๋ฐ ์ €๋Š” Suspense๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•œ์ ์ด ์—†๋Š”๊ฑธ์š”?

ํ˜„์žฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•˜๊ณ  ์žˆ๋Š” ReactDOMServer ๋Š” ์•„์ง Suspense ๋ฅผ ์ง€์›ํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ ๋‹ค์‹œ ์ •์˜ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ํ˜„์žฌ serverside rendering์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์•„๋ฌด๋Ÿฐ next api ์—†์ด ๊ทธ๋ƒฅ ํ•จ์ˆ˜ํ˜ธ์ถœ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด next.js๋Š” default๋กœ serverside rendering์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์†Œ์Šค ์ฝ”๋“œ์—” suspense๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์†Œ์Šค ์ฝ”๋“œ์—” Relay๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•ด์˜ค๋Š” useLazyLoadQuery ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Relay๊ณต์‹๋ฌธ์„œ์—์„œ ์ฐพ์€๊ฑด Relay๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ suspense๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค ์ž…๋‹ˆ๋‹ค.


Untitled

useLazyLoadQuery | Relay

tutorial์—์„œ๋„ Suspense ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์› ์„ ๋•Œ http ํ†ต์‹ ์—์„œ๋Š” response๋ฅผ ๋ฐ›์•„์™”์ง€๋งŒ ํ™”๋ฉด์—์„œ ๋ Œ๋”๋ง์„ ๋ชปํ•ด์ฃผ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Relay ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์œ„ํ•ด์„  Suspense๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, Next.js12 ์—์„œ๋Š” suspense๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒŒ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค.

Suspense๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋‡จ? ์ด๋ ‡๊ฒŒ next/dynamic ์œผ๋กœ suspense์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

Untitled

๊ทธ๋Ÿผ Suspense๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Next.js์˜ Suspense ๋Š” ๋ฆฌ์•กํŠธ ๊ธฐ๋ฐ˜์˜ Suspense์ด๋ฏ€๋กœ, ๋ฒ„์ „ ๋ณ„๋กœ ์–ด๋””๊นŒ์ง€ ์ง€์›ํ•ด์ฃผ๋Š”์ง€๋ฅผ ํ™•์ธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

React17์—์„œ๋Š” Suspense๊ฐ€ ๊ณต์‹์ ์œผ๋กœ ์ง€์›๋˜์ง€ ์•Š์ง€๋งŒ Next 12๋ฒ„์ „์—์„œ React17์˜ suspense๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” CSR ์ „๋žต์—์„œ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ถ€๋ถ„์„ ํ•ด๊ฒฐ ํ•˜๊ธฐ ์œ„ํ•ด SuspenseWapper ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด csr์‹œ์ ์— relay ์ฟผ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import React, { Suspense } from 'react' interface SuspenseWrapperProps { fallback: JSX.Element children: React.ReactNode } const isBrowser = typeof window !== 'undefined' const SuspenseWrapper: React.FunctionComponent<SuspenseWrapperProps> = ({ fallback, children, ...restProps }) => { if (isBrowser) { return <Suspense fallback={fallback}>{children}</Suspense> } return fallback } export default SuspenseWrapper

Next.js12 (React17์„ ์‚ฌ์šฉํ•  ๋•Œ) ์—์„œ๋Š” React์—์„œ ์ œ๊ณตํ•˜๋Š” Suspense API ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. SuspenseWrapper ๋Š” fallback๊ณผย children์„ props๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๋˜ํ•œย ...restProps๋ฅผ ํ†ตํ•ด ์ถ”๊ฐ€์ ์ธ props๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์ปดํฌ๋„ŒํŠธ๋Š”ย isBrowser๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ์ฝ”๋“œ๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์ด๋ผ๋ฉด,ย Suspenseย ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌย children์„ ๋ Œ๋”๋งํ•˜๊ณ , ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์ค‘์—๋Š”ย fallback์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์ด ์•„๋‹ˆ๋ผ๋ฉด,ย fallback๋งŒ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์ •์˜๋œย SuspenseWrapperย ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ์ž„ํฌํŠธํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก export ๋ฉ๋‹ˆ๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ํ™˜๊ฒฝ์—์„œ Suspense ๊ธฐ๋Šฅ์ด ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์œ ์ €๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ๊ฐ ํŽ˜์ด์ง€ ๋ฐ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ์ „๋žต์„ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ๊ฐ€์•ผ ํ• ๊นŒ์š”?

๋ชจ๋“  ํŽ˜์ด์ง€์™€ ์ปดํฌ๋„ŒํŠธ๋“ค์„ CSR ๋กœ ๊ฐ€์ ธ๊ฐ€์•ผ ํ• ๊นŒ์š”? ๋งŒ์•ฝ ๋ชจ๋“  ํŽ˜์ด์ง€์™€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ Œ๋”๋ง (CSR)์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค๋ฉด, Next.js๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง (SSR) ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” Next.js์˜ ๊ฐ€์žฅ ํฐ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋ฅผ ์ œํ•œํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. (= ๋ฌผ๋ก  ์ œ๊ฐ€ relay๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•˜๊ธฐ์ „ Next ํ”„๋กœ์ ํŠธ์ด๊ธฐ๋„ ํ•˜์ง€๋งŒ)

์ œ๊ฐ€ ์„ ํƒํ•œ ๋ฐฉ๋ฒ•์€,

์ตœ์ดˆ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง์‹œ SSR์„ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋”ฉ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค. SSR์€ ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™” (SEO)๋ฅผ ๊ฐœ์„ ํ•˜๊ณ  ์ดˆ๊ธฐ ๋กœ๋”ฉ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. Relay ์ฟผ๋ฆฌ๋Š” CSR๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

Untitled

import * as React from 'react'; import { useLazyLoadQuery } from 'react-relay'; import { graphql } from 'relay-runtime'; import dynamic from 'next/dynamic'; import SuspenseWrapper from '@app/components/SuspenseWrapper'; export interface RelayProps { } const DynamicRelay = dynamic(()=> import('@app/components/SuspenseRelay'),{ssr:false,loading: ()=><p>loading...</p>} ) function Relay (props: RelayProps) { return ( <> <h1>Relay Page on SSR </h1> <SuspenseWrapper fallback={<p>loading...</p>}> <DynamicRelay/> </SuspenseWrapper> </> ); } export default Relay
  • React์™€ Relay๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  • GraphQL ์ฟผ๋ฆฌ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ฟผ๋ฆฌ๋Š”ย pingย ํ•„๋“œ๋งŒ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ์ด ์ฟผ๋ฆฌ๋Š”ย useLazyLoadQueryย ํ›…์„ ํ†ตํ•ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
import * as React from 'react'; import { graphql, useLazyLoadQuery } from 'react-relay'; import {SuspenseRelayQuery}from "./../../../__generated__/SuspenseRelayQuery.graphql" interface SuspenseRelayProps { } const RelayQuery = graphql` query SuspenseRelayQuery{ ping } ` const SuspenseRelay: React.FunctionComponent< SuspenseRelayProps> = () => { const data = useLazyLoadQuery<SuspenseRelayQuery>(RelayQuery,{}) console.log("Data",data) return <> <div> <h1>SuspenseRelay</h1> </div> </>; }; export default SuspenseRelay

SSR์—์„œ ์ด๋ฃจ์–ด์งˆ Suspense์ž…๋‹ˆ๋‹ค.

import React, { Suspense } from 'react' interface SuspenseWrapperProps { fallback: JSX.Element children: React.ReactNode } const isBrowser = typeof window !== 'undefined' const SuspenseWrapper: React.FunctionComponent<SuspenseWrapperProps> = ({ fallback, children, ...restProps }) => { if (isBrowser) { return <Suspense fallback={fallback}>{children}</Suspense> } return fallback } export default SuspenseWrapper

Untitled

์ด๋กœ์จ ๋ฒ„์ „๊ฐ„์˜ suspense ์ง€์› ์ƒํƒœ๋ฅผ ์•Œ๊ฒŒ ๋˜์—ˆ๋˜๋Š” ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Hi, I'm Hyunsu ๐Ÿ‘‹

Profile Image

์•ˆ๋…•ํ•˜์„ธ์š”. ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ฃผํ˜„์ˆ˜์ž…๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ํ’๋ถ€ํ•˜๊ณ  ๊ฐ€์น˜ ์žˆ๋Š” ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋Š” ์ผ์— ๋ฟŒ๋“ฏํ•จ์„ ๋Š๋‚๋‹ˆ๋‹ค.

์˜ต์‹œ๋””์–ธ(Obsidian)์—์„œ ํ˜„์žฌ ๋ธ”๋กœ๊ทธ๋กœ ํ•˜๋‚˜์”ฉ ๊ธ€์„ ์˜ฎ๊ธฐ๋Š” ๊ณผ์ •์— ์žˆ์–ด์š”. โ˜•๏ธ ๐Ÿ‘ฉโ€๐Ÿ’ป โ›ท

Github on ViewReach Me Out