Skip to content

Commit

Permalink
feat: 에러바운더리, api 에러바운더리 생성[#82]
Browse files Browse the repository at this point in the history
  • Loading branch information
j2h30728 committed Jul 15, 2024
1 parent b22997f commit d701d00
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/shared/error/ApiErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ErrorInfo } from 'react';
import { ApiError } from '../api/customError';
import ErrorBoundary from './ErrorBoundary';

class ApiErrorBoundary extends ErrorBoundary {
static getDerivedStateFromError(error: Error): {
hasError: boolean;
error: Error;
} {
if (error instanceof ApiError) {
return { hasError: true, error };
}
throw error;
}

componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
if (error instanceof ApiError) {
this.setState({ hasError: true, error });
console.error(
'API Error:',
error.message,
error.status,
error.data,
errorInfo
);
} else {
throw error;
}
}
}

export default ApiErrorBoundary;
72 changes: 72 additions & 0 deletions src/shared/error/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
Component,
ComponentType,
createElement,
ErrorInfo,
ReactNode,
} from 'react';

export type FallbackProps = {
error: Error | null;
resetErrorBoundary: () => void;
};

type ErrorBoundaryProps = {
children: ReactNode;
fallback: ComponentType<FallbackProps>;
onReset?: () => void;
};

type ErrorBoundaryState = {
hasError: boolean;
error: Error | null;
};

const initialState: ErrorBoundaryState = {
hasError: false,
error: null,
};

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false, error: null };
this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
}
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}

componentDidCatch(error: Error, errorInfo: ErrorInfo) {
this.setState({ hasError: true, error });
console.error(error, errorInfo);
}

resetErrorBoundary() {
const { error } = this.state;

if (error !== null) {
this.props.onReset?.();

this.setState(initialState);
}
}

render() {
const { state, props, resetErrorBoundary } = this;
const { hasError, error } = state;
const { fallback, children } = props;

if (hasError) {
const fallbackProps: FallbackProps = {
error,
resetErrorBoundary,
};
return createElement(fallback, fallbackProps);
}

return children;
}
}

export default ErrorBoundary;
41 changes: 41 additions & 0 deletions src/shared/error/FallbackComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import styled from 'styled-components';
import { ApiError } from '../api/customError';
import { Button } from '../ui';
import { FallbackProps } from './ErrorBoundary';

const FallbackComponent = ({ error, resetErrorBoundary }: FallbackProps) => (
<Container>
<h3 id="title">오류가 발생했습니다</h3>
{error instanceof ApiError && <p id="message">{error.message}</p>}
<Button color="SECONDARY-DASH" onClick={resetErrorBoundary}>
재시도
</Button>
</Container>
);

export default FallbackComponent;

const Container = styled.div`
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
width: 100%;
height: 100vh;
padding: 10px;
gap: 10px;
background-color: ${({ theme }) => theme.COLORS.BACKGROUND};
border-radius: 10px;
#title {
font-size: 30px;
color: #bb3c3c;
font-weight: 700;
}
#message {
display: flex;
flex-direction: column;
justify-content: space-around;
font-size: 20px;
}
`;

0 comments on commit d701d00

Please sign in to comment.