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}
</>
)}
>
<ErrorAfter2s />
</ErrorBoundary>
)
<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}>
<ErrorAfter2s />
</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}>
<ErrorAfter2s />
</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]}
fallback={(props) => <>{props.error.message}</>}
>
<ErrorAfter2s />
</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}>
<ErrorAfter2s />
</ErrorBoundary>
)
props.shouldCatch
shouldCatch๋ ์กฐ๊ฑด์ ๋ฐ๋ผ <ErrorBoundary/>
๊ฐ ์๋ฌ๋ฅผ ์ก์์ง ๊ฒฐ์ ํฉ๋๋ค.
Boolean, ErrorConstructor, Callback์ 3๊ฐ์ง ๊ธฐ์ค์ ๋ฐ์ผ๋ฉฐ ๊ธฐ๋ณธ๊ฐ์ true
์
๋๋ค.
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect, createElement } from 'react'
export const Example = () => {
return (
<ErrorBoundary
fallback={({ error }) => (
<>Parent ErrorBoundary fallback: {error.message}</>
)}
>
<ErrorBoundary
shouldCatch={false}
fallback={({ error }) => (
<>Child ErrorBoundary fallback: {error.message}</>
)}
>
<CustomErrorAfter2s />
</ErrorBoundary>
</ErrorBoundary>
)
}
๋ฐฐ์ด์ ํตํด ์ฌ๋ฌ ์กฐ๊ฑด์ ์ ์ฉํ ์๋ ์์ต๋๋ค.
import { ErrorBoundary } from '@suspensive/react'
import { useState, useEffect, createElement } from 'react'
const Example = () => {
return (
<ErrorBoundary
fallback={({ error }) => (
<>Parent ErrorBoundary fallback: {error.message}</>
)}
>
<ErrorBoundary
shouldCatch={[
false,
CustomError,
(error) => error instanceof CustomError,
]}
fallback={({ error }) => (
<>Child ErrorBoundary fallback: {error.message}</>
)}
>
<CustomErrorAfter2s />
</ErrorBoundary>
</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 <>No error</>
}
๋ค์์ <ErrorBoundary/>
๋ฅผ ์ ์ดํ๊ธฐ
<ErrorBoundary/>
์ <ErrorBoundaryGroup/>
๊ณผ ์ฌ์ฉํ๋ฉด ๋ ๊ฐ๋ ฅํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. <ErrorBoundaryGroup/>
๋ก ๋ค์์ <ErrorBoundary/>
๋ฅผ ์ ์ดํ์ธ์.
์์ธํ ๋ด์ฉ์ <ErrorBoundaryGroup/>
ํ์ด์ง์์ ์๊ฐํฉ๋๋ค.