๐Ÿ‘€ Suspensive v2์—์„œ์˜ ๋ณ€๊ฒฝ์„ ํ™•์ธํ•˜์„ธ์š”. ๋”๋ณด๊ธฐ โ†’
๋ฌธ์„œ๋ณด๊ธฐ@suspensive/reactwrap

wrap

wrap์€ @suspensive/react์—์„œ ์ œ๊ณตํ•˜๋Š” Suspense, ErrorBoundary, ErrorBoundaryGroup ๋“ฑ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค.

import { wrap, ErrorBoundaryGroup } from '@suspensive/react'
import { useSuspenseQuery } from '@suspensive/react-query'
 
export const Page = wrap
  .ErrorBoundaryGroup({ blockOutside: true })
  .ErrorBoundary({
    fallback: ({ error }) => <PageErrorFallback message={error.message} />,
  })
  .Suspense({ fallback: <PageSkeleton /> })
  .on(
    // <ErrorBoundaryGroup />, <ErrorBoundary />, <Suspense />์— ๊ฐ์‹ธ์ง„ <Page/> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    () => {
      const { data: postList } = useSuspenseQuery({
        queryKey: ['posts'],
        queryFn: () =>
          fetch(`https://example.com/posts`).then((res) => res.json()),
      })
 
      return (
        <>
          <ErrorBoundaryGroup.Consumer>
            {(group) => <button onClick={group.reset}>Reset all posts</button>}
          </ErrorBoundaryGroup.Consumer>
          {postList.map((post) => (
            <PostItem id={post.id} />
          ))}
        </>
      )
    }
  )
 
const PostItem =
  wrap
    .ErrorBoundary({ fallback: ({ error }) => <>{error.message}</> })
    .Suspense({ fallback: <PostSkeleton /> }).on <
  { id: string } >
  // <ErrorBoundary/>, <Suspense/>์— ๊ฐ์‹ธ์ง„ <PostItem/> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  ((props) => {
    const { data: post } = useSuspenseQuery({
      queryKey: ['posts', props.id],
      queryFn: () =>
        fetch(`https://example.com/posts/${props.id}`).then((res) =>
          res.json()
        ),
    })
 
    return <>{post.title}</>
  })
import { wrap, ErrorBoundaryGroup } from '@suspensive/react'
import { useSuspenseQuery } from '@suspensive/react-query'
import { useState, createElement } from 'react'

import { getPost, getPosts } from './api'

export const Example = wrap
  .ErrorBoundaryGroup({ blockOutside: true })
  .ErrorBoundary({ fallback: ({ error }) => <div>{error.message}</div> })
  .Suspense({ fallback: <div>Loading...</div> })
  .on(() => {
    const { data: postList } = useSuspenseQuery({
      queryKey: ['posts'],
      queryFn: getPosts,
    })

    return (
      <>
        <ErrorBoundaryGroup.Consumer>
          {(group) => <button onClick={group.reset}>Reset all posts</button>}
        </ErrorBoundaryGroup.Consumer>

        {postList.map((post) => (
          <PostItem key={post.id} id={post.id} />
        ))}
      </>
    )
  })

const PostItem = wrap
  .ErrorBoundary({
    fallback: ({ error }) => (
      <div
        style={{
          border: '1px solid black',
          padding: 10,
          margin: 10,
          color: 'red',
        }}
      >
        {error.message}
      </div>
    ),
  })
  .Suspense({ fallback: <div>Loading...</div> })
  .on<{ id: number }>((props) => {
    const { data: post } = useSuspenseQuery({
      queryKey: ['posts', props.id],
      queryFn: () => getPost(props.id),
    })
    const [throwError, setThrowError] = useState(false)

    return (
      <div style={{ border: '1px solid black', padding: 10, margin: 10 }}>
        <p>{post.title}</p>
        <button onClick={() => setThrowError(true)}>Throw error</button>
        {createElement(() => {
          if (throwError) {
            throw new Error('Error!')
          }

          return null
        })}
      </div>
    )
  })