Skip to Content
๐Ÿ‘€ Suspensive v3์—์„œ์˜ ๋ณ€๊ฒฝ์„ ํ™•์ธํ•˜์„ธ์š”. ๋”๋ณด๊ธฐ
๋ฌธ์„œ๋ณด๊ธฐ@suspensive/react-query<SuspenseQuery/>

SuspenseQuery

๊ฐ™์€ depth์—์„œ Suspense๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ด ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  1. data-fetching๋งŒ์„ ์œ„ํ•œ UserInfo, PostList์™€ ๊ฐ™์€ depth๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— prop-drilling๋„ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.
  2. Suspense, ErrorBoundary์˜ ๋ฒ”์œ„ ๋ณ€๊ฒฝ๋„ ๊ฐ„๋‹จํ•ด์ง‘๋‹ˆ๋‹ค. query์˜ ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๋„ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.
  3. Page ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ data-fetching์„ ๋ชจ๋‘ ๊ด€์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๋ถ€์˜ ์ปดํฌ๋„ŒํŠธ๋Š” presentationalํ•˜๋ฏ€๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
import { SuspenseQuery } from '@suspensive/react-query' import { Suspense, ErrorBoundary } from '@suspensive/react' import { PostListItem, UserProfile } from '~/components' const PostsPage = ({ userId }) => ( <ErrorBoundary fallback={({ error }) => <>{error.message}</>}> <Suspense fallback={'loading...'}> <SuspenseQuery {...userQueryOptions(userId)}> {({ data: user }) => <UserProfile key={user.id} {...user} />} </SuspenseQuery> <SuspenseQuery {...postsQueryOptions(userId)} select={(posts) => posts.filter(({ isPublic }) => isPublic)} > {({ data: posts }) => posts.map((post) => <PostListItem key={post.id} {...post} />) } </SuspenseQuery> </Suspense> </ErrorBoundary> )
import { useState } from 'react'
import { ErrorBoundary, Suspense } from '@suspensive/react'
import { SuspenseQuery } from '@suspensive/react-query'
import { PostListItem } from './PostListItem'
import { UserProfile } from './UserProfile'
import { postsQueryOptions, userQueryOptions } from './queries'

export const Example = () => {
  const [userId, setUserId] = useState(1)
  const [showAllPosts, setShowAllPosts] = useState(false)

  return (
    <ErrorBoundary fallback={({ error }) => <>{error.message}</>}>
      <button onClick={() => setUserId((id) => id - 1)} disabled={userId === 1}>
        Previous User
      </button>
      <button
        onClick={() => setUserId((id) => id + 1)}
        disabled={userId === 10}
      >
        Next User
      </button>
      <Suspense fallback={<div>Loading...</div>}>
        <SuspenseQuery {...userQueryOptions(userId)}>
          {({ data: user }) => <UserProfile key={user.id} {...user} />}
        </SuspenseQuery>

        <label>
          <input
            type="checkbox"
            checked={showAllPosts}
            onChange={() => setShowAllPosts((showAllPosts) => !showAllPosts)}
          />
          Show All Posts
        </label>

        <SuspenseQuery
          {...postsQueryOptions(userId)}
          select={(posts) =>
            posts.filter(({ isPublic }) => showAllPosts || isPublic)
          }
        >
          {({ data: posts }) => (
            <ol>
              {posts.map((post) => (
                <PostListItem key={post.id} {...post} />
              ))}
            </ol>
          )}
        </SuspenseQuery>
      </Suspense>
    </ErrorBoundary>
  )
}

๋™๊ธฐ: useSuspenseQuery๊ฐ€ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š์Œ

๊ธฐ์กด์˜ useSuspenseQuery๋Š” ํ›…์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€๋ชจ์— Suspense, ErrorBoundary๋ฅผ ๋ฐฐ์น˜ํ•˜๊ธฐ ์œ„ํ•ด UserInfo, PostList์™€ ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ UserInfo, PostList ๋‚ด๋ถ€์—์„œ ๋˜์ ธ์งˆ suspense์™€ error๊ฐ€ ์žˆ์„์ง€ ์˜ˆ์ธกํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

// posts/page.tsx import { Suspense, ErrorBoundary } from '@suspensive/react' import { UserInfo } from './components/UserInfo' import { PostList } from './components/PostList' const PostsPage = ({ userId }) => ( <ErrorBoundary fallback={({ error }) => <>{error.message}</>}> <Suspense fallback={'loading...'}> <UserInfo userId={userId} />{' '} {/* ๋‚ด๋ถ€์ ์œผ๋กœ Suspense๋ฅผ ๋ฐœ์ƒํ•  ์ง€ ์˜ˆ์ƒํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. */} <PostList userId={userId} />{' '} {/* ๋‚ด๋ถ€์ ์œผ๋กœ Suspense๋ฅผ ๋ฐœ์ƒํ•  ์ง€ ์˜ˆ์ƒํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. */} </Suspense> </ErrorBoundary> )
// posts/components/UserInfo.tsx import { useSuspenseQuery } from '@suspensive/react-query' import { UserProfile } from '~/components' // ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” UserInfo๋ผ๋Š” ์ด๋ฆ„๋งŒ์œผ๋กœ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ Suspense๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ง€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. const UserInfo = ({ userId }) => { // data-fetching๋งŒ์„ ์œ„ํ•œ ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. const { data: user } = useSuspenseQuery(userQueryOptions(userId)) return <UserProfile {...user} /> }
// posts/components/PostList.tsx import { useSuspenseQuery } from '@suspensive/react-query' import { PostListItem } from '~/components' // ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” PostList๋ผ๋Š” ์ด๋ฆ„๋งŒ์œผ๋กœ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ Suspense๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ง€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. const PostList = ({ userId }) => { // data-fetching๋งŒ์„ ์œ„ํ•œ ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. const { data: posts } = useSuspenseQuery({ ...postsQueryOptions(userId), select: (posts) => posts.filter(({ isPublic }) => isPublic), }) return ( <> {posts.map((post) => ( <PostListItem {...post} /> ))} </> ) }

๋ฒ„์ „ ๊ธฐ๋ก

VersionChanges
v3.0.0networkMode๋Š” 'always'๋กœ ๊ณ ์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ v3๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ธฐ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.
์ˆ˜์ •๋œ ๋‚ ์งœ: