๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
React

[React] Suspense์„ ์‚ฌ์šฉํ•ด ์„ ์–ธ์ ์œผ๋กœ ๋กœ๋”ฉ ํ™”๋ฉด ๊ตฌํ˜„ํ•˜๊ธฐ

by LasBe 2023. 3. 23.
๋ฐ˜์‘ํ˜•

๐Ÿ“’ Suspense์„ ์‚ฌ์šฉํ•ด ์„ ์–ธ์ ์œผ๋กœ ๋กœ๋”ฉ ํ™”๋ฉด ๊ตฌํ˜„ํ•˜๊ธฐ


๋ฆฌ์•กํŠธ์˜ Suspense๋Š” React 16 ๋ฒ„์ „์—์„œ ์ฒ˜์Œ์œผ๋กœ ์„ ๋ณด์ธ ํ›„
18 ๋ฒ„์ „์œผ๋กœ ์˜ค๋ฉฐ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
 
์ด ๊ธ€์—์„œ๋Š” React 18์—์„œ์˜ Suspense๋ฅผ ์™œ, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.


์ด๋ฒˆ์— ๋ฉ”์ด์ € ๋ฒ„์ „์ด ์—…๋ฐ์ดํŠธ ๋œ react-query v5์—์„œ Suspense๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‹ฌ๋ผ์กŒ๋Š”์ง€ ๋‹ค์Œ ๊ธ€๋กœ ๋น ๋ฅด๊ฒŒ ์‚ดํŽด๋ณด์„ธ์š”!

react-query v5 ์ฃผ์š” ๋ณ€๊ฒฝ์  ์•Œ์•„๋ณด๊ธฐ feat. Suspense, ErrorBoundary


๐Ÿ“Œ Suspense๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

๋ฆฌ์•กํŠธ๊ฐ€ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋„์ž…ํ•˜๋ฉฐ ๋‚ด์„ธ์šด ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋Š” ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ž…๋‹ˆ๋‹ค.
 
์šฐ์„  ๋ณธ๊ฒฉ์ ์ธ ์„ค๋ช…์— ์•ž์„œ ๋Œ€๋น„๋˜๋Š” ๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ฐจ์ด์— ๋Œ€ํ•ด ์„ค๋ช…๋“œ๋ฆฝ๋‹ˆ๋‹ค.
 

๐Ÿ”Ž ๋ช…๋ นํ˜• vs ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ

๊ฐ€์žฅ ํ”ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๊ธฐ๋กœ๋Š” ํ•œ ์ž‘์—…์— ๋Œ€ํ•ด
๋ช…๋ นํ˜•์€ ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€,
์„ ์–ธํ˜•์€ ๋ฌด์—‡์„ ํ•  ๊ฒƒ์ธ์ง€ ๋ฐฉ๋ฒ•์˜ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
 
์ •๋ง ์• ๋งคํ•œ ํ‘œํ˜„์ž…๋‹ˆ๋‹ค.
 
์šฐ์„  ์ฝ”๋“œ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
 

// ::๋ช…๋ นํ˜•::
const array = [ 1, 2, 3 ]
let sum = 0;

array.forEach( num => sum += num );

console.log(sum);


// ::์„ ์–ธํ˜•::
const array = [ 1, 2, 3 ];
// ์–ด๋”˜๊ฐ€์— ์„ ์–ธ๋˜์–ด ๋ฐฐ์—ด์˜ ํ•ฉ์„ ๊ตฌํ•ด์ฃผ๋Š” arraySum ํ•จ์ˆ˜
const sum = arraySum(array);
console.log(sum)

๋ช…๋ นํ˜•์€ ๊ณผ์ •์„ ๋Š˜์–ด๋†“์•„ ๊ฒฐ๊ณผ๋ฅผ ๋„์ถœํ•˜๋Š” ๊ฒƒ์ด๊ณ 
์„ ์–ธํ˜•์€ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์œ„ํ•œ ๊ธฐ๋Šฅ์„ ์ถ”์ƒํ™”ํ•˜์—ฌ ๊ณผ์ •์€ ์ˆจ๊ธฐ๊ณ  ๋ฌด์—‡์„ ํ•  ๊ฒƒ์ธ์ง€์— ์ง‘์ค‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
 
์ฆ‰, ์„ ์–ธํ˜•์€ ์–ด๋”˜๊ฐ€์— ๋ช…๋ นํ˜•์œผ๋กœ ์ถ”์ƒํ™”๋œ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด ๊ณผ์ •์€ ์ˆจ๊ธฐ๊ณ ,
๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ํ–‰์œ„์—๋งŒ ์ง‘์ค‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
 
์˜ˆ๋ฅผ ๋“ค์–ด console.log()๋‚˜ alert()๋„ ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€๋Š” ๊ด€์‹ฌ ์—†์ด,
"์ฝ˜์†”์„ ์ฐ๊ธฐ ์œ„ํ•ด", "์–ผ๋Ÿฟ์„ ๋„์šฐ๊ธฐ ์œ„ํ•ด" ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ๋ฆฌ์•กํŠธ์™€ ์„ ์–ธํ˜•

๊ทธ๋Ÿผ ๋Œ์•„์™€์„œ ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ถ”์ƒํ™”๋œ hook์ด๋ผ๋Š” ๊ฒƒ์„ ์ด์šฉํ•ด ์„ ์–ธ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
 
์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋ ค ํ•  ๋•Œ๋Š” useState(),
๋ถ€์ˆ˜ํšจ๊ณผ(side effect)๋ฅผ ๊ด€๋ฆฌ ๋ฐ ์‚ฌ์šฉํ•˜๋ ค ํ•  ๋•Œ๋Š” useEffect(),
์‹ฌ์ง€์–ด ๊ฐ„๋‹จํ•œ ๋ฌธ๋ฒ•๋งŒ ๋งž์ถฐ์ฃผ๋ฉด ์•Œ์•„์„œ ๋ Œ๋”๋ง๊นŒ์ง€ ํ•ด์ฃผ๋‹ˆ ์—ฌ๊ธฐ์ €๊ธฐ ์„ ์–ธํ˜•์ด ์•„๋‹ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
 

export const ConditionalRendering = () => {
  const [state, setState] = useState<{ name: string }>();

  useEffect(() => {
    promiseFun().then(response => setState({ name: response }));
  }, []);
  
  return state ? <Component name={state.name} /> : <Loading />;
};

๊ทธ๋Ÿฐ๋ฐ ์ง€๊ธˆ๊นŒ์ง€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ fetching ํ•ด์˜ค๋ฉฐ ๋กœ๋”ฉ ์ƒํƒœ์˜ ํ™”๋ฉด์„ ๊ทธ๋ฆด ๋•Œ๋Š”
์œ„์™€ ๊ฐ™์ด ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ์ด์šฉํ•œ ๋ช…๋ นํ˜• ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ์™”์Šต๋‹ˆ๋‹ค.
 
์ด๋ ‡๊ฒŒ ๊ฐ ์ƒํ™ฉ๋ณ„๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค ๋ณด๋ฉด ์ƒํƒœ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋งŽ์•„์งˆ์ˆ˜๋ก
๊ฒฝ์šฐ์˜ ์ˆ˜๋„ ๋น„๋ก€ํ•ด์„œ ๋Š˜์–ด๋‚˜ ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•ด์ง€๊ณ  ๋ณต์žกํ•ด์งˆ ๊ฒƒ์ด ๋ป”ํ•ฉ๋‹ˆ๋‹ค.
 
๊ทธ๋Ÿฐ๋ฐ Suspense๋ฅผ ์ด์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const SubComponent = () => {
  const { data } = useQuery(['serverData'], getFetchData, { suspense: true });
  return <div>{data}</div>;
};

const ParantComponent = () => {
  return (
    <Suspense fallback={ <Loading /> }>
      <SubComponent />
    </Suspense>
  );
};

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ Suspense๋กœ ๊ฐ์‹ธ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋์ž…๋‹ˆ๋‹ค.
 
๋กœ๋”ฉํ™”๋ฉด ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์— ์„ ์–ธ์ ์œผ๋กœ Suspense๋ฅผ ์ด์šฉํ•จ์œผ๋กœ์จ
๋กœ๋”ฉ์— ๊ด€๋ จ๋œ ๋กœ์ง์„ ์œ„์ž„ํ•˜๊ฒŒ ๋˜๊ณ ,
์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๋Š” ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด
๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ์— ๋”ฐ๋ฅธ ์ด๋“์„ ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
 
 

๐Ÿ“Œ Suspense ์‚ฌ์šฉ๋ฐฉ๋ฒ•

๐Ÿ”Ž ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

์ฒ˜์Œ์—” ๋Œ€์ถฉ ํ™•์ธํ•˜๊ณ  ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด Suspense๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์„ ์ค„ ์•Œ์•˜๋Š”๋ฐ
์•Œ๊ณ  ๋ณด๋‹ˆ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” ํŠน์ • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

  • Relay: graphQL์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • SWR: ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • React-Query: ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • Recoil: ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Suspense์™€ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•ด ๋กœ๋”ฉ ๋กœ์ง์„ ์งค ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š”
Suspense๊ฐ€ Promise๋ฅผ catch ํ•˜๋Š”๋ฐ
์œ„์™€ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ Promise ์ƒํƒœ๋ฅผ throw ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
 
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— Promise๊ฐ€ resolve ๋˜๊ธฐ ์ „๊นŒ์ง€ Suspense๊ฐ€ fallback UI๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ”Ž React-Query + Suspense ์‚ฌ์šฉ๋ฐฉ๋ฒ•

graphQL์€ ๋ชจ๋ฅด๋‹ˆ๊นŒ ํŒจ์Šคํ•˜๊ณ , Recoil์€ ํด๋ผ์ด์–ธํŠธ ์ „์—ญ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ๋งŒ ๋‹ด๋‹นํ•˜๊ฒŒ ํ•˜๊ณ ,
๋‚จ์€ ๊ฑด ๋‘˜ ๋ฟ์ธ๋ฐ ๋Œ€์„ธ๋Š” React-Query๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์˜ˆ์ œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
 
react-query์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์€ ์•„๋ž˜ ๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

 

[React] react-query, ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 

โšก๏ธ react-query๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ  ๋ฆฌ์•กํŠธ์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ฌด์ˆ˜ํžˆ ๋งŽ์Šต๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ redux, recoil ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ๋Š”๋ฐ, ๋Œ€๋ถ€๋ถ„ ์ด๋Ÿฌํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ

lasbe.tistory.com


const queryClient = new QueryClient();

root.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>
);

์•ฑ์˜ ๋ฃจํŠธ ๋ถ€๋ถ„์— Provider ์„ค์ •์„ ํ•ด์ฃผ์–ด React-Query ์‚ฌ์šฉ ์ค€๋น„๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.
 

const { data } = useQuery(["serverData"], () => getFetchData(2000), {
    suspense: true
});

useQuery ํ›…์—๋Š” ( [key], fetch ์ฝœ๋ฐฑ ํ•จ์ˆ˜, ์˜ต์…˜) ์„ ์ธ์ž๋กœ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
 
ํ‚ค๋Š” ๋ฐฐ์—ดํ˜•ํƒœ๋กœ ๋„ฃ์–ด์ค˜์•ผ ํ•˜๋ฉฐ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—๋Š” ๋ฐ์ดํ„ฐ๋ฅผ fetch ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๊ณ 
์˜ต์…˜์—๋Š” suspense: true ์˜ต์…˜์„ ์ค˜์•ผ ๋ฐ์ดํ„ฐ fetching์‹œ Suspense๊ฐ€ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
 

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      suspense: true,
    },
  },
})

๋งŒ์•ฝ ์ „์—ญ์œผ๋กœ useQuery ํ›…์— suspense ์˜ต์…˜์„ ์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด ํด๋ผ์ด์–ธํŠธ์˜ defaultOptions๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
 
 

import { useQuery } from "@tanstack/react-query";
import { Suspense } from "react";

const getFetchData = async ({ delay }: { delay: number }) => {
  await new Promise((resolve) => setTimeout(resolve, delay));
  const data = await fetch(
    "https://jsonplaceholder.typicode.com/posts/1"
  ).then((response) => response.json());
  return data;
};

type ComponentType = {
  delay: number;
};

const SubComponent = ({ delay }: ComponentType) => {
  const { data } = useQuery(
    ["serverData"],
    () => getFetchData({ delay: delay }),
    { suspense: true }
  );
  return <div>{JSON.stringify(data)}</div>;
};

export const App = () => {
  return (
    <Suspense fallback={<h1>Loading...</h1>}>
      <SubComponent delay={2000} />
    </Suspense>
  );
};

๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•ด ๋ณธ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.
 
jsonplaceholder์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ fetch ํ•ด์˜ค๊ณ  ์˜๋„์ ์œผ๋กœ ๋”œ๋ ˆ์ด๋ฅผ ์ค˜ ์›ํ™œํ•œ ๋กœ๋”ฉํ™”๋ฉด ํ‘œ์‹œ๋ฅผ ๋„์™”์Šต๋‹ˆ๋‹ค.
 
ํ™•์ธํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ๋กœ๋”ฉํ™”๋ฉด ํ‘œ์‹œ๊ฐ€ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ“Œ ๋ Œ๋”๋ง ์™„๋ฃŒ ์‹œ์ ์ด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ

๋ Œ๋”๋ง ์™„๋ฃŒ ์‹œ์ ์ด ์„œ๋กœ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค์„ Suspense๋ฅผ ์ด์šฉํ•ด
๋กœ๋”ฉ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ ค๊ณ  ํ•  ๋•Œ ํฌ๊ฒŒ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ”Ž ๋‹ค๋ฅธ Suspense์— ๋ฐฐ์น˜

 

<>
  <h1>Title</h1>
  <Suspense fallback={<h2>Title Loading...</h2>}>
    <Title delay={2000} />
  </Suspense>
  <hr />
  <h1>Body</h1>
  <Suspense fallback={<h2>Body Loading...</h2>}>
    <Body delay={6000} />
  </Suspense>
</>

์„œ๋กœ ์—ฐ๊ด€์„ฑ์ด ์ ์€ ์ปดํฌ๋„ŒํŠธ์ผ ๊ฒฝ์šฐ ๋‹ค๋ฅธ Suspense ์˜์—ญ์œผ๋กœ ๋ฌถ์–ด
๊ฐœ๋ณ„์ ์ธ ๋กœ๋”ฉํ™”๋ฉด์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”Ž ๊ฐ™์€ Suspense ์˜์—ญ์— ๋ฐฐ์น˜

<>
  <h1>Post</h1>
  <Suspense fallback={<h2>Post Loading...</h2>}>
    <Title delay={2000} />
    <Body delay={6000} />
  </Suspense>
</>

๊ฐ™์€ Suspense ์•ˆ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐฐ์น˜ํ•˜๋ฉด
์ผ์ฒด๊ฐ ์žˆ๊ฒŒ ๋กœ๋”ฉ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ ์น˜๋ช…์ ์ธ ๋‹จ์ ์ด ํ•˜๋‚˜ ์žˆ์Šต๋‹ˆ๋‹ค.
 
๋ฐ”๋กœ ์•ž์„  ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์•„๋ฌด๋ฆฌ ๋นจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋”๋ผ๋„
๊ฐ€์žฅ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์ „๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
 
์œ„์—์„œ๋„ Title ์ปดํฌ๋„ŒํŠธ๊ฐ€ 2์ดˆ ๋งŒ์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™”์–ด๋„
6์ดˆ์˜ ์ง€์—ฐ์‹œ๊ฐ„์„ ๊ฐ–๊ณ  ์žˆ๋Š” Body์— ์˜ํ•ด ๋ Œ๋”๋ง์ด ์•ˆ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”Ž Suspense In Suspense

์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๊ฐœ๋ณ„์ ์ธ Suspense๋ฅผ ์ด์šฉํ•˜๋ฉด n๊ฐœ์˜ Loading UI๊ฐ€ ํ‘œ์‹œ๋˜๋Š”๋ฐ,
์–ด๋–ค ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๊ธด ์‹œ๊ฐ„์ด ๊ฑธ๋ ค๋„ ํ•˜๋‚˜์˜ ๋กœ๋”ฉ์œผ๋กœ ๊ตฌํ˜„ํ•ด์•ผ ๋  ๋•Œ๊ฐ€ ์žˆ์„ ๊ฑฐ๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
 
๊ทธ๋Ÿด ๋•Œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ๊ธด ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
 

<>
  <h1>Post</h1>
  <Suspense fallback={<h2>Post Loading...</h2>}>
    <Suspense fallback={<h2>Profile Image Loading...</h2>}>
      <Image delay={8000} />
    </Suspense>
    
    <Title delay={2000} />
    <Body delay={4000} />
  </Suspense>
</>

Promise ์ƒํƒœ๋ฅผ throw ํ•˜๋ฉด ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด Suspense๊ฐ€ catchํ•˜๊ธฐ ๋•Œ๋ฌธ์—
๋‚ด๋ถ€์— ์„ ์–ธ๋œ Suspense๊ฐ€ Promise ์ƒํƒœ๋ฅผ catch ํ•ด์„œ ๋ถ€๋ชจ Suspense๊นŒ์ง€ ๋„๋‹ฌํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
 
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•˜์œ„ Promise๊ฐ€ resolve ๋˜์ง€ ์•Š์•˜์–ด๋„ ์ž์‹ Suspense์—๊ฒŒ ๋กœ๋”ฉ ๊ถŒํ•œ์„ ์œ„์ž„ํ•ด์„œ
์ด๋ฏธ fetching์ด ๋๋‚œ ๋ถ€๋ชจ Suspense๋Š” ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
 
์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๋กœ๋”ฉ ๋กœ์ง์„ ์ง ๋‹ค๋ฉด ์ˆ˜๋งŽ์€ fallback UI ๋Œ€์‹  ์—ฐ๊ด€์„ฑ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ๋ฆฌ
์ผ๊ด€์„ฑ ์žˆ๊ณ  ์ˆœ์ฐจ์ ์ธ ๋ Œ๋”๋ง์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.
 

 

๐Ÿ“Œ Suspense + ErrorBoundary ํ”„๋กœ์ ํŠธ ๋„์ž…

Suspense์™€ ErrorBoundary๋ฅผ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ๋„์ž…ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋” ๋‹ค์–‘ํ•˜๊ณ  ์–ด๋ ค์šด ๋ฌธ์ œ๋“ค๊นŒ์ง€ ํ•จ๊ป˜ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋” ๊ด€์‹ฌ์ด ์žˆ์œผ์‹œ๋‹ค๋ฉด ๋‹ค์Œ ๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

ErrorBoundary & Suspense, ๊ฑฐ์˜ ์™„๋ฒฝํ•œ ์‚ฌ์šฉ๋ฐฉ๋ฒ• ๊ฐ€์ด๋“œ

 

[React] ErrorBoundary & Suspense, ๊ฑฐ์˜ ์™„๋ฒฝํ•œ ์‚ฌ์šฉ๋ฐฉ๋ฒ• ๊ฐ€์ด๋“œ

๐Ÿ“’ ErrorBoundary & Suspense, ๊ฑฐ์˜ ์™„๋ฒฝํ•œ ์‚ฌ์šฉ๋ฐฉ๋ฒ• ๊ฐ€์ด๋“œํ•˜๋‚˜์˜ Errorboundary ๋ฐฑ๊ฐœ์˜ try-catch ์•ˆ ๋ถ€๋Ÿฝ๋‹ค.ํ”„๋ก ํŠธ ๊ฐœ๋ฐœ์„ ๊ณ„์†ํ•˜๋‹ค ๋ณด๋‹ˆ ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์„ ๋งˆ์ฃผ์น˜๊ฒŒ ๋˜์—ˆ๊ณ , ๊ทธ์— ๋”ฐ๋ฅธ ์ ์ ˆํ•œ ํ™”๋ฉด ํ‘œํ˜„์˜ ์ค‘

lasbe.tistory.com

ErrorBoundary๋ฅผ ํ†ตํ•œ ์„ ์–ธ์ ์ธ ์—๋Ÿฌ ํ•ธ๋“ค๋ง, react-query๋ฅผ ์ด์šฉํ•œ ์žฌํ˜ธ์ถœ ๋ฐฉ๋ฒ•

 

[React] ErrorBoundary๋ฅผ ํ†ตํ•œ ์„ ์–ธ์ ์ธ ์—๋Ÿฌ ํ•ธ๋“ค๋ง, react-query๋ฅผ ์ด์šฉํ•œ ์žฌํ˜ธ์ถœ ๋ฐฉ๋ฒ•

โšก ๋ฆฌ์•กํŠธ์—์„œ์˜ ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋ฆฌ์•กํŠธ์˜ ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ ์ ˆํ•œ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด๊ฐ€ ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ํ‰์†Œ API ํ˜ธ์ถœ ๋กœ์ง์— try - catch

lasbe.tistory.com

 

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€


์˜คํ”ˆ ์ฑ„ํŒ