ErrorBoundary
์ด ์ปดํฌ๋ํธ๋ children์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์ ์ดํ ์ ์์ต๋๋ค.
props.fallback
<ErrorBoundary/>
์ children์ error๊ฐ ๋ฐ์ํ๋ฉด error๋ ์กํ๊ณ fallback์ด ๋ ๋๋ง๋ฉ๋๋ค.
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect } from 'react'
const Example = () => (
<ErrorBoundary
fallback={(props) => (
<>
<button onClick={props.reset}>Try again</button>
{props.error.message}
</>
)}
>
<ErrorAfter4s />
</ErrorBoundary>
)
const ErrorAfter4s = () => {
const [asyncState, setAsyncState] = useState<{ isError: true; error: Error } | { isError: false; error: null }>({
isError: false,
error: null,
})
useEffect(() => {
setTimeout(() => {
setAsyncState({ isError: true, error: { status: 401, message: 'unauthorized' } })
}, 4000)
}, [])
if (asyncState.isError) {
throw asyncState.error
}
return <>No error</>
}
<ErrorBoundary/>
'์ fallback๋ก ์ ๋ฌํ ์ปดํฌ๋ํธ ์ ์ํ๊ธฐ
ErrorBoundaryFallbackProps
<ErrorBoundary/>
'์ fallback์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ์ ๋ฌํ๊ณ ์ถ๋ค๋ฉด ErrorBoundaryFallbackProps
ํ์
์ ํ์ฉํด ์ฝ๊ฒ ์ปดํฌ๋ํธ๋ฅผ ์ ์ธ ํ ์ ์์ต๋๋ค.
import type { ErrorBoundaryFallbackProps } from '@suspensive/react'
const ErrorBoundaryFallback = ({ reset, error }: ErrorBoundaryFallbackProps) => (
<>
<button onClick={reset}>reset</button>
{error.message}
</>
)
const Example = () => (
<ErrorBoundary fallback={ErrorBoundaryFallback}>
<ErrorAfter4s />
</ErrorBoundary>
)
<ErrorBoundary/>
fallback props์ prop drilling ์์ด ์ฌ์ฉํ๊ธฐ
useErrorBoundaryFallbackProps
error
๊ฐ์ฒด์ reset
๋ฉ์๋์ ์ฌ์ฉํ๋ ค๋ ์ปดํฌ๋ํธ๊ฐ ์ค์ฒฉ๋๋ฉด prop drilling์ ํผํ ์ ์์ต๋๋ค.
์ด ๋, useErrorBoundaryFallbackProps
์ ํตํด, prop drilling ์์ด reset
๋ฉ์๋์ error
๊ฐ์ฒด์ ์ ๊ทผํ ์ ์์ต๋๋ค.
import { ErrorBoundary, useErrorBoundaryFallbackProps } from '@suspensive/react'
const Nested = () => {
const { reset, error } = useErrorBoundaryFallbackProps()
return (
<>
<button onClick={reset}>Try again</button>
{error.message}
</>
)
}
// ์ฌ๊ธฐ์ fallbackProp ์ ์ ๋ฌํ ํ์๊ฐ ์์ด์ง๋๋ค!
const ErrorBoundaryFallback = () => <Nested />
const Example = () => (
<ErrorBoundary fallback={ErrorBoundaryFallback}>
<Error />
</ErrorBoundary>
)
props.resetKeys
<ErrorBoundary/>
์ fallback ์ธ๋ถ์ ์๋ ์ปดํฌ๋ํธ๊ฐ <ErrorBoundary/>
๋ฅผ resetํ๋ ค๋ฉด resetKeys๋ฐฐ์ด์ resetKey๋ฅผ ํ ๋นํ๋ฉด ๋ฉ๋๋ค. resetKeys๋ ๋ฐฐ์ด์ ํ๋ ์ด์์ ์์๊ฐ ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ง ์๋ํฉ๋๋ค. useEffect์ ์ข
์์ฑ ๋ฐฐ์ด์ด ์๋ํ๋ ๋ฐฉ์๊ณผ ๊ฐ์ด resetKeys๋ก ๋งค ๋ ๋๋ง๋ง๋ค ์ ๋ฐฐ์ด์ ์ฃผ์
ํ๋ ๊ฒ์ ๊ฑฑ์ ํ ํ์๋ ์์ต๋๋ค.
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect } from 'react'
const Example = () => {
const [resetKey, setResetKey] = useState(0)
return (
<>
<button onClick={() => setResetKey((prev) => prev + 1)}>Try again</button>
<ErrorBoundary resetKeys={[resetKey]}>
<ErrorAfter4s />
</ErrorBoundary>
</>
)
}
props.onReset
<ErrorBoundary/>
๊ฐ resetํ ๋ ๋จผ์ ํธ์ถ๋๋ callback์
๋๋ค. @tanstack/react-query์๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
import { ErrorBoundary } from '@suspensive/react'
import { QueryErrorResetBoundary } from '@tanstack/react-query'
const Example = () => (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallback={(props) => (
<>
<button onClick={props.reset}>Try again</button>
{props.error.message}
</>
)}
>
<Page />
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
)
props.onError
<ErrorBoundary/>
๊ฐ error๋ฅผ ์ก์ ๋ ํธ์ถ๋๋ callback์
๋๋ค.
import { ErrorBoundary } from '@suspensive/react'
const logError = (error: Error, info: ErrorInfo) => {
// ...
}
const Example = (
<ErrorBoundary fallback={ErrorBoundaryFallback} onError={logError}>
<Error />
</ErrorBoundary>
)
useErrorBoundary
useErrorBoundary().setError
<ErrorBoundary/>
์ children์์ useErrorBoundary().setError์ ์ฌ์ฉํด throw ์์ด๋ <ErrorBoundary/>
์์ Error๋ฅผ ์๋๋ก ํ ์ ์์ต๋๋ค.
import { ErrorBoundary, useErrorBoundary } from '@suspensive/react'
import { useEffect } from 'react'
const Example = () => (
<ErrorBoundary fallback={ErrorBoundaryFallback}>
<SetErrorAfterFetch />
</ErrorBoundary>
)
const SetErrorAfterFetch = () => {
const errorBoundary = useErrorBoundary()
useEffect(() => {
fetchSomething().then(
(response) => {},
(error) => errorBoundary.setError(error) // instead of throw inside
)
}, [])
return <>...</>
}
withErrorBoundary
deprecated: wrap.ErrorBoundary().on์ ๋์ ์ฌ์ฉํ์ธ์
withErrorBoundary๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ๋ฅผ <ErrorBoundary/>
๋ก ์ฝ๊ฒ ๋ํํ ์ ์์ต๋๋ค.
์๋์ ๊ฐ์ด withErrorBoundary๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฅผ ๊ฐ์ธ๊ธฐ ์ํด ๋ถํ์ํ ์ฝ๋๋ฅผ ๋ง๋ค ํ์๊ฐ ์์ต๋๋ค.
withErrorBoundary์ ๋ ๋ฒ์งธ ์ธ์๋ children์ด ์๋ <ErrorBoundary/>
์ props์
๋๋ค.
import { withErrorBoundary, useErrorBoundary } from '@suspensive/react'
const Example = withErrorBoundary(
function Component() {
const errorBoundary = useErrorBoundary()
return <>...</>
},
{ fallback: ErrorBoundaryFallback }
)
๋ค์์ <ErrorBoundary/>
๋ฅผ ์ ์ดํ๊ธฐ
<ErrorBoundary/>
์ <ErrorBoundaryGroup/>
๊ณผ ์ฌ์ฉํ๋ฉด ๋ ๊ฐ๋ ฅํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. <ErrorBoundaryGroup/>
๋ก ๋ค์์ <ErrorBoundary/>
๋ฅผ ์ ์ดํ์ธ์.
์์ธํ ๋ด์ฉ์ <ErrorBoundaryGroup/>
ํ์ด์ง์์ ์๊ฐํฉ๋๋ค.